1.线程同步方式synchronised
为什么要线程同步,举个简单的例子,你的银行账户一共有3000块钱,你的手里有这3000块的存折,你的妻子手里有这3000块的银行卡,你拿着存折到银行取2000块钱,与此同时,你的妻子拿着银行卡到取款机取2000块,你们两个人同时访问了同一个银行账户,访问的时候,余额都是3000块,当进行取钱操作的时候,系统会判断你的账户里的钱足够你和你妻子取出的数目,这样,账户就会同时给你和你妻子一人2000块,然后账户余额剩下1000,显然这对银行来说是亏损,为了避免这个情况,就需要线程同步。当你取钱的时候,访问这个账户的余额的同时给这个账户加上一把锁,在此期间其他人无法访问这个账户,直到这个锁失效,这样就达到了线程同步的目的。
看下面例子:
package Thread;
public class TestSync implements Runnable {
Timer timer = new Timer();
public static void main(String[] args) {
TestSync test = new TestSync();
Thread thread1 = new Thread(test);
Thread thread2 = new Thread(test);
thread1.setName("t1");
thread2.setName("t2");
thread1.start();
thread2.start();
}
@Override
public void run() {
timer.addNum(Thread.currentThread().getName());
}
}
class Timer{
private int num = 0;
public void addNum(String name){
num++;
try{
Thread.sleep(1);
}catch(Exception e){
}
System.out.println(name+",你是第"+num+"个访问timer的线程");
}
}
输出结果: t1,你是第2个访问timer的线程
t2,你是第2个访问timer的线程
很明显这不是我们想要的结果,期待的结果应该是:t1,你是第1个访问timer的线程,t2,你是第2个访问timer的线程。为什么会出现这种情况呢?当t1执行addNum的时候,num 变成了1,然后程序睡眠了1毫秒,此时t2访问addNum模块,num再次+1变为2,当t1继续执行的时候,num就变成了2.如果想要期待的输出结果,就需要线程同步,在上面的addNum方法上加一把锁。让addNum方法在同一时间只能有一个线程访问。代码如下
class Timer{
private int num = 0;
public void addNum(String name){
synchronized (this) {
num++;
try{
Thread.sleep(1);
}catch(Exception e){
}
System.out.println(name+",你是第"+num+"个访问timer的线程");
}
}
}
当t1执行addNum方法时候,synchronized给当前对象上了锁,其他线程只能等到t1访问结束,才能访问addNum方法。
输出结果: t1,你是第1个访问timer的线程
t2,你是第2个访问timer的线程
2.死锁
简单的来说就是两个拥有锁的资源互相访问。形成了死锁。看例子程序
package Thread;
public class TestDeadLock implements Runnable{
public int flag = 1;
static Object o1 = new Object(),o2 = new Object();
@Override
public void run() {
System.out.println("flag=="+flag);
if(flag == 1){
synchronized(o1){
try{
Thread.sleep(500);
}catch(Exception e){}
synchronized(o2){
System.out.println("1");
}
}
}
if(flag == 0){
synchronized(o2){
try{
Thread.sleep(500);
}catch(Exception e){}
synchronized(o1){
System.out.println("0");
}
}
}
}
public static void main(String[] args) {
TestDeadLock test1 = new TestDeadLock();
TestDeadLock test2 = new TestDeadLock();
test1.flag = 1;
test2.flag = 0;
Thread t1 = new Thread(test1);
Thread t2 = new Thread(test2);
t1.start();
t2.start();
}
}
上面程序中两个线程就形成了死锁,解决的办法是同步的颗粒度粗一点,不要给对象加锁,最好给代码块加锁。至于其他的解决方法也很多,就介绍了。