在java多线程编程中,我们需要对java对象中的资源进行同步管理,确保在同一时刻,只能由同一线程访问类或者对象中的资源,这样可以防止由于几个线程共享同一资源导致不可知的后果。
方法之一就是利用资源锁(synchronized),废话少说,先上例子
例子一
public class S_1 {
public static void main(String[] args) {
for(int i=0;i<5;i++){
new Thread_1().start();
}
}
}
class Thread_1 extends Thread{
@Override
public synchronized void run() {
for(int i=0;i<100;i++){
System.out.println(i);
}
}
}
例子二:
public class S_2 {
public static void main(String[] args) {
for(int i=0;i<5;i++){
new Thread_2().start();
}
}
}
class Thread_2 extends Thread{
@Override
public void run(){
synchronized(this){
for(int i=0;i<100;i++){
System.out.println(i);
}
}
}
}
例子三:
public class S3 {
public static void main(String[] args) {
for(int i=0;i<5;i++){
new Thread_3().start();
}
}
}
class Thread_3 extends Thread{
public synchronized static void show(){
for(int i=0;i<100;i++){
System.out.println(i);
}
}
@Override
public void run(){
show();
}
}
例子四:
public class S_4 {
public static void main(String[] args) {
for(int i=0;i<5;i++){
String lock = "lock";
new Thread_4(lock).start();
}
}
}
class Thread_4 extends Thread{
private String lock ;
public Thread_4(String lock){
this.lock = lock ;
}
@Override
public void run(){
synchronized(lock){
for(int i=0;i<100;i++){
System.out.println(i);
}
}
}
}
以上四个例子是用五个线程从0-99进行打印,他们都是按照先后顺序从0-99进行打印的吗?如果你的答案是按顺序依次打印的话,那你就错了,下边我一一来讲解下
例子一,没有按照先后顺序进行打印。我们对run方法进行了加锁,按理说是该按照先后顺序进行打印的,但是为什么结果与我们想象的不一样呢?由于我们起五个线程的时候,我们创建了五个Thread_1对象,这样每个线程都获取了一个对象,每个线程都获取了自己对象中run方法的锁,所以,这里的资源锁是没有意义的,如果要让这里的锁起作用,除非该Thread_1是单例模式的,这样这些线程都共享一个对象,才会按照先后顺序获取锁
例子二,没有按照先后顺序进行打印。我们对run方法中的一部分代码进行了synchronized块保护,也应该按照每个线程依次打印,但为什么还是没有依次打印呢?由于我们synchronized(this)中的this在五个线程中是没有共享的,五个线程中的this都不一样,这样相当于对五个对象进行资源块进行保护,五个线程依然能够同时获取synchronized(this)方法中的代码执行的锁
例子三,按照先后顺序打印。这个例子可以和例子一对应起来看,我们是在show方法上加的锁,并且show方法是static的,这样这里方法就是类方法,被所以对象共享的,当我们起五个线程,这五个线程对show方法是共享的,而且该方法被加锁了,当线程来访问的时候,首先看这个方法是否被其他线程使用,如果正在被其他对象使用,对不起,你先等着,等下一个线程用完了,退出了的时候,线程池中轮到你的时候,你才能执行该方法
例子四,按照先后顺序打印。这个例子可以和例子四对应起来看,首先我们来看下例子4,类Thread_4是一个继承Thread的线程类,他有一个私有变量lock,在其run方法中,我们用锁块对要打印的语句进行保护,我们在启动线程的时候,通过构造方法,给Thread_4的lock变量进行赋值,由于我们启动的五个线程中,每个Thread对象的lock变量的值都是同一个,即五个线程共享变量lock,所以要执行被synchronized方法锁起来的语句,也必须获得相应的锁才能够执行,对比例子一种,this的值在每个线程中不一样的
最后总结
如果我们想通过synchronized来修辞方法,来达到在同一时刻,该方法只能被同一线程访问的话,有两个条件
条件一:线程对象是一个单例类
条件二:synchronized修饰的方法是static的
如果我们想通过synchronized方法来达到在同一时刻,被保护的语句块只能被同一线程访问,其条件是
synchronized方法中传入的对象必须是共享的,即传入的对象必须是一样的
希望这篇博文对你有用,如果我对synchronized认识不到位的地方,请多多指教