package unit_fifteen; public class Foo { private int x = 100; public int getX() { return x; } public int fix(int y) { x = x - y; return x; } } package unit_fifteen; public class MyRunnable implements Runnable { private Foo foo =new Foo(); public static void main(String[] args) { MyRunnable r = new MyRunnable(); Thread ta = new Thread(r,"Thread-A"); Thread tb = new Thread(r,"Thread-B"); ta.start(); tb.start(); } public void run() { for (int i = 0; i < 3; i++) { this.fix(30); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " :当前foo对象的x值= " + foo.getX()); } } public int fix(int y) { return foo.fix(y); } } Thread-B :当前foo对象的x值= 40 Thread-A :当前foo对象的x值= 10 Thread-A :当前foo对象的x值= -20 Thread-B :当前foo对象的x值= -50 Thread-B :当前foo对象的x值= -80 Thread-A :当前foo对象的x值= -80
从结果发现,这样的输出值明显是不合理的,且结果是变动的,原因是两个线程不加控制的访问Foo对象并修改其数据所致;如果要保持结果的合理性,只需要达到一个目的,就是将对Foo的访问加以限制,每次只能有一个线程在访问
Java中一个对象只有一个锁。所以,如果一个线程获得该锁,就没有其他线程可以获得锁,直到第一个线程释放(或返回)锁;释放锁是指持锁线程退出了synchronized同步方法或代码块;线程睡眠时,它所持的任何锁都不会释放;线程可以获得多个锁。比如,在一个对象的同步方法里面调用另外一个对象的同步方法,则获取了两个对象的同步锁;同步损害并发性,应该尽可能缩小同步范围。同步不但可以同步整个方法,还可以同步方法中一部分代码块
当然,同步方法也可以改写为非同步方法,但功能完全一样的,例如:
public synchronized int getX() {
return x++;
}
package unit_fifteen; public class Test { public static void main(String[] args) { User u = new User("张三", 100); MyThread t1 = new MyThread("线程A", u, 20); MyThread t2 = new MyThread("线程B", u, -60); MyThread t3 = new MyThread("线程C", u, -80); MyThread t4 = new MyThread("线程D", u, -30); MyThread t5 = new MyThread("线程E", u, 32); MyThread t6 = new MyThread("线程F", u, 21); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); t6.start(); } } class MyThread extends Thread { private User u; private int y = 0; MyThread(String name, User u, int y) { super(name); this.u = u; this.y = y; } public void run() { u.oper(y); } } class User { private String code; private int cash; User(String code, int cash) { this.code = code; this.cash = cash; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } /** * 业务方法 * @param x 添加x万元 */ public synchronized void oper(int x) { try { Thread.sleep(10L); this.cash += x; System.out.println(Thread.currentThread().getName() + "运行结束,增加“" + x +"”,当前用户账户余额为:" + cash); Thread.sleep(10L); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public String toString() { return"User{" + "code='" + code + '\'' + ", cash=" + cash + '}'; } }
与
public int getX() {
synchronized (this) {
return x;
}
}
package unit_fifteen; public class Test { public static void main(String[] args) { User u = new User("张三", 100); MyThread t1 = new MyThread("线程A", u, 20); MyThread t2 = new MyThread("线程B", u, -60); MyThread t3 = new MyThread("线程C", u, -80); MyThread t4 = new MyThread("线程D", u, -30); MyThread t5 = new MyThread("线程E", u, 32); MyThread t6 = new MyThread("线程F", u, 21); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); t6.start(); } } class MyThread extends Thread { private User u; private int y = 0; MyThread(String name, User u, int y) { super(name); this.u = u; this.y = y; } public void run() { u.oper(y); } } class User { private String code; private int cash; User(String code, int cash) { this.code = code; this.cash = cash; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } /** * 业务方法 * * @param x 添加x万元 */ public void oper(int x) { try { Thread.sleep(10L); synchronized (this) { this.cash += x; System.out.println(Thread.currentThread().getName() +"运行结束,增加“" + x +"”,当前用户账户余额为:" + cash); } Thread.sleep(10L); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public String toString() { return"User{" + "code='" + code + '\'' + ", cash=" + cash + '}'; } }
效果是完全一样的
要同步静态方法,需要一个用于整个类对象的锁,这个对象是就是这个类(XXX.class)
例如:
public static synchronized int setName(String name){
Xxx.name = name;
}
等价于
public static int setName(String name){
synchronized(Xxx.class){
Xxx.name = name;
}
}
注意:对于同步,要时刻清醒在哪个对象上同步,这是关键
死锁对Java程序来说,是很复杂的,也很难发现问题。当两个线程被阻塞,每个线程在等待另一个线程时就发生死锁
package unit_fifteen; public class Test { public static void main(String[] args) { DeadlockRisk dead = new DeadlockRisk(); MyThread t1 = new MyThread(dead, 1, 2); MyThread t2 = new MyThread(dead, 3, 4); MyThread t3 = new MyThread(dead, 5, 6); MyThread t4 = new MyThread(dead, 7, 8); t1.start(); t2.start(); t3.start(); t4.start(); } } class MyThread extends Thread { private DeadlockRisk dead; private int a, b; MyThread(DeadlockRisk dead, int a, int b) { this.dead = dead; this.a = a; this.b = b; } @Override public void run() { dead.read(); dead.write(a, b); } } class DeadlockRisk { private static class Resource { public int value; } private Resource resourceA = new Resource(); private Resource resourceB = new Resource(); public int read() { synchronized (resourceA) { System.out.println("read():" + Thread.currentThread().getName() + "获取了resourceA的锁!"); synchronized (resourceB) { System.out.println("read():" + Thread.currentThread().getName() + "获取了resourceB的锁!"); return resourceB.value + resourceA.value; } } } public void write(int a, int b) { synchronized (resourceB) { System.out.println("write():" + Thread.currentThread().getName() + "获取了resourceA的锁!"); synchronized (resourceA) { System.out.println("write():" + Thread.currentThread().getName() + "获取了resourceB的锁!"); resourceA.value = a; resourceB.value = b; } } } }