同步代码块
- 同步锁
为了保证每个线程都能正常执行原子操作,Java引入了线程同步机制。
同步监听对象/同步锁/同步监听器/互斥锁
对象的同步只是一个概念,可以想象为在对象上标记了一个锁
Java运行程序使用任何对象作为同步监听对象,但是一般我们把当前并发的同步资源作为同步监听对象
注意!在任何时候,最多允许一个线程拥有同步锁,谁拿到锁进入代码块,其他的线程只能在外面等着.
synchronized(this){
//todo
}
class ImplementDemo implements Runnable{
private int num = 50;
public void run() {
for (int i = 0;i<50;i++) {
synchronized(this){
if (num > 0) {
System.out.println(Thread.currentThread().getName() + "吃了编号为" + num +"的苹果" );
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
num--;
}
}
}
}
}
public class ExtendsDemo {
public static void main(String[] args) {
ImplementDemo im = new ImplementDemo();
new Thread(im,"小A").start();
new Thread(im,"小B").start();
new Thread(im,"小C").start();
}
}
同步方法
同步方法使用synchronized修饰的方法叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着.
此时的同步锁是谁:
对于非static方法,同步锁就是this
对于static方法,我们使用当前方法所在的类的字节码对象(ImplementDemo.class)
public synchronized void (){
//todo
}
class ImplementDemo implements Runnable{
private int num = 50;
public void run() {
for (int i = 0;i<50;i++) {
eatMethod();
}
}
public synchronized void eatMethod() {
if (num > 0) {
System.out.println(Thread.currentThread().getName() + "吃了编号为" + num +"的苹果" );
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
num--;
}
}
}
public class ExtendsDemo {
public static void main(String[] args) {
ImplementDemo im = new ImplementDemo();
new Thread(im,"小A").start();
new Thread(im,"小B").start();
new Thread(im,"小C").start();
}
}
synchronized的好与坏
- 好处
保证了多线程并发访问时的同步操作,避免线程的安全性问题.
- 缺点
使用synchronized的方法/代码块的性能比不用要低一些.
++建议尽量减小synchronized的作用域++
- 举例StringBuffer与StringBuilder
public synchronized StringBuffer append(Object obj){
super.append(String.valueOf(obj));
return this;
}
public StringBuilder append(Object obj){
return append(String.valueOf(obj));
}