先看下面例子 再说为什么要线程的同步
class TestThreadCount{
static int cnt=0;
public static void main(String[] args)
{
final int NUM=5000;
Thread[] threads =new Thread[NUM];
for (int i=0;i<NUM;i++) {
threads[i]=new Thread() {
public void run(){
cnt++;
try {Thread.sleep(1);}catch(InterruptedException ex) {}
}
};
}
for(int i=0;i<NUM;i++)threads[i].start();
try {Thread.sleep(1);}catch(InterruptedException ex) {}
System.out.printf("%d %b\n",cnt,cnt=NUM);
}
}
先阅读这个程序 创建了5000个线程, for循环中 run 执行线程执行之后运行的代码,每次计数1 所以当线程行完毕之后 cnt应该是5000
4998 false 4999 false 也有时候是5000 为什么会这样
简单的说 线程之间是共享内存的 当一个线程执行的时候 例如 cnt=23 它还没来得及++ 马上操作系统调度第二个线程执行 这样就导致了有时候数字不对 这时候需要用到线程间的同步
java引入了对象互斥锁概念,来保证共享数据操作的完整性
每个对象都对应于一个监视器,它上面一个称为“互斥锁”的标记/状态,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
简答的说就是它上面有一个状态,这个状态的每一个变量都有这个状态,同时,每一时刻最多被某一个线程使用。。这个可以比喻成商场买衣服时候的试衣间,换衣服,这个时刻只能 有一个人进去,别人就不能用了,除非这个人把这个标记给释放掉。
在线程中就是只能有一个线程同时拥有这个锁 /状态
关键字 synchronized用来与对象互斥锁联系
synchronized用法
代码片段
synchronized(对象){...}相当于对象加锁 别的线程进不来 这段代码有人叫临界代码,进了这个临界区,别人是进不来的
对某个方法:
synchronized放在方法声明中
public synchronized void push(char c){...}
相当于对synchronized(this)表示整个方法为同步方法
import java.util.Date;
class SynCounter2{
public static void main(String[] args) {
Num num=new Num();
Thread counter1= new Counter(num);
Thread counter2= new Counter(num);
Thread counter3= new Counter(num);
try {
Thread.sleep(100);
}catch(InterruptedException e) {}
}
}
class Num{
private int x=0;
private int y=0;
synchronized void increase() {//它执行完之后 另一个线程才可以过来
x++;
y++;
}
synchronized boolean testEquals() {
boolean ok=(x==y);
System.out.println(x+","+y+":"+ok);
return ok;
}
}
class Counter extends Thread{
private Num num;
private boolean stop = false;
public void stopCounter(){
stop=true;
}
Counter(Num num){
this.num=num;
this.start();
}
public void run(){
//while(!stop){
//num.increase();
//}
for(int i=0;i<10;i++) {
num.increase();
}
num.testEquals();
}
}
结果
10,10:true
20,20:true
30,30:true 也即 线程之间没有串扰。但有时候会出现21,21;true 的情况这个不明白为什么(以后解决把)
用wait()方法可以释放对象锁
用notify()或notifyAll()可以让等待得一个或所有线程进如就绪状态
Java里面可以将wait notify放在synchronized里
JAVA中 synchronized代码被执行期间,线程调用对象得wait()方法,会释放对象锁标志,然后进入等待状态
notify()方法 也是这样 表示按当前操作做完了 别的线程可以来工作了
线程的死锁 彼此互相等待
第一个对象启动 上锁 第二个对象启动 上锁 调用方法的时候,第一个对象与第二个对象合作 但是得等待第二个对象得锁打开 这时候没有相应得操作 与此类似 第二个对象和第一个对象合作,也在等第二个对象开锁 这时候就死锁了
class Worker{
int id;
public Worker(int id) {this.id=id;}
synchronized void doTaskWithCopperator(Worker other) {
try {Thread.sleep(500);}catch(Exception e) {}
synchronized(other) {
System.out.println("dong"+id);
}
}
}
class DeadLockDemo{
public static void main(String[] args) {
Worker w1=new Worker(1);
Worker w2=new Worker(2);
Thread td1=new Thread(()-> {w2.doTaskWithCopperator(w1);});
Thread td2=new Thread(()-> {w2.doTaskWithCopperator(w1);});
td1.start();
td2.start();
}
}