文章目录
相信大家都听说过线程安全问题,在学习操作系统的时候有一个知识点是临界资源,简单的说就是一次只能让一个进程操作的资源,但是我们在使用多线程的时候是并发操作的,并不能控制同时只对一个资源的访问和修改,想要控制那么有几种操作,今天我们就来讲讲第一种方法:线程同步块或者线程同步方法(synchronized)
synchronized
关键字的使用public class Sychor {
public void insert(Thread thread) {
for (int i = 0; i < 10; i++) {
System.out.println(thread.getName() + "输出: " + i);
}
}
public static void main(String[] args) {
final Sychor sychor = new Sychor();
Thread t1 = new Thread() {
public void run() {
sychor.insert(Thread.currentThread());
};
};
Thread t2 = new Thread() {
public void run() {
sychor.insert(Thread.currentThread());
};
};
t1.start();
t2.start();
}
}
其中输出结果为下图
从上面的结果可以看出这里的两个线程是同时执行
insert()
方法的,下面我们在原有的代码上添加synchronized
关键字看看效果如何,代码如下: public class Sychor { public synchronized void insert(Thread thread) { for (int i = 0; i < 10; i++) { System.out.println(thread.getName() + "输出: " + i); } } public static void main(String[] args) { final Sychor sychor = new Sychor(); Thread t1 = new Thread() { public void run() { sychor.insert(Thread.currentThread()); }; }; Thread t2 = new Thread() { public void run() { sychor.insert(Thread.currentThread()); }; }; t1.start(); t2.start(); } } 上面程序的运行结果我就不列出来,自己可以试试,总之就是加上了synchronized
关键字使得线程是一个一个的执行的,只有先执行完一个线程才能执行了另外一个线程。
当然上面的我们使用的是线程同步方法,我们可以使用线程同步块,这两个相比线程同步块更加灵活,只需要将需要同步的代码放在同步块中即可,代码如下; public class Sychor { public void insert(Thread thread) { synchronized (this) { for (int i = 0; i < 10; i++) { System.out.println(thread.getName() + "输出: " + i); } } } public static void main(String[] args) { final Sychor sychor = new Sychor(); Thread t1 = new Thread() { public void run() { sychor.insert(Thread.currentThread()); }; }; Thread t2 = new Thread() { public void run() { sychor.insert(Thread.currentThread()); }; }; t1.start(); t2.start(); } } 从上面的代码中可以看出这种方式更加灵活,只需要将需要同步的代码方法在同步块中,不需要同步的代码放在外面
从上面的结果可知,此时线程同步块根本不起作用,因为他们调用的是不同对象的insert方法,获得锁是不一样的
this
,我们都知道this
在一个类中的含义对象锁
是为非静态方法
实现线程同步的,因为我们在调用非静态方法
的时候需要创建对象,因此这里使用的是对象锁。但是我们调用静态方法
的时候直接使用的是类名
直接调用,并没有用到对象,因此我们需要用到类锁
,直接使用类名.class
获取即可。public class myThread{
public static void display(){
synchronized(myThread.class){
for(int i=0;i<10;i++){
System.out.println(i);
}
}
}
}
static
同步方法或者其中的同步块,那么一定要使用同一个对象,如果调用的是static同步方法或者其中的同步块那么一定要使用同一个类去调用
static
同步方法,而另外一个线程访问的是非static的同步方法,此时这两个是不会发生冲突的,因为一个是类的锁,一个是对象的锁
jvm
会自动释放当前线程所占用的锁,因此不会出现由于异常导致死锁的现象