自定义线程类中的实例变量针对其他线程有共享和不共享之分,这是线程间交互时的很重要的一个技术点。
举例:
public class MYThread extends Thread {
private int count = 5;
public MYThread(String name) {
super();
this.setName(name);//设置线程的名字
}
@Override
public void run() {
super.run();
while (count > 0) {
count -- ;
System.out.println("由 "+this.currentThread().getName()+" 计算,count= "+count);
}
}
}
public class TetsMYThread {
public static void main(String[] args) {
MYThread t1 = new MYThread("A");
MYThread t2 = new MYThread("B");
MYThread t3 = new MYThread("C");
t1.start();
t2.start();
t3.start();
}
}
上面创建三个线程,每个线程都有自己的count变量,自己减少自己的变量的count的值,这种情况是变量不共享的,不是多个线程访问同一个实例变量。
改进代码:
public static void main(String[] args) {
MYThread t = new MYThread();
Thread t1 = new Thread(t,"A");
Thread t2 = new Thread(t,"B");
Thread t3 = new Thread(t,"C");
Thread t4 = new Thread(t,"D");
Thread t5 = new Thread(t,"E");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
public class MYThread extends Thread {
private int count = 5;
@Override
public void run() {
super.run();
count--;
System.out.println("由 " + this.currentThread().getName()
+ " 计算,count= " + count);
}
}
A C两个线程同时打印count的值是3,说明两个线程同时对count进行处理,产生“非线程安全问题”。我们想要打印的是结果不是重复的,而是依次减少的。
在某些jvm中 i-- 操作分为3步骤:
1.取出原有的i值
2.计算i-1
3.对i赋值
这三个步骤中,如果有多个线程同时访问,那么一定会出现非线程安全问题。
再改进代码:
public class MYThread extends Thread {
private int count = 5;
@Override
synchronized public void run() {
super.run();
count--;
System.out.println("由 " + this.currentThread().getName()
+ " 计算,count= " + count);
}
}
在run方法中加上synchronized关键字,使多个线程在执行run方法的时候,以队列的方式进行处理,当一个线程调用run方法前,先判断run方法有没有被上锁,如果上锁,说明有其他线程在调用run方法,必须等待其他线程对run方法调用结束才能执行run方法,这样实现了排队调用的目的,也就实现了对count依次--,synchronized可以对任意对象及方法加上锁,而枷锁的这段代码叫做 “互斥区”或“临界区”。
再次理解
当一个线程想要执行同步方法中的代码,线程首先尝试去拿这把锁,如果能拿到,那么这个线程就可以执行synchronized里面的代码,如果拿不到,那么这个线程就会不断的尝试去拿这把锁,直到拿到为止,注意这里是多个线程同时去争抢这把锁。。。