多线程 03


1. synchronized运用实例

(1)问doOther方法的执行需要等待doSome方法的结束吗?

package 多线程;
/*问doOther方法的执行需要等待doSome方法的结束吗?
 *不需要,因为synchronized用在了实例方法doSome上,表示锁this,
 *this就是指 MyClass m
 *而doOther方法没有synchronized,不需要排队
 *执行结果:
doSome start
doOther start
doOther end
(5秒后)
 doSome end*/
public class T1 {

	public static void main(String[] args) {
		MyClass m = new MyClass();
		Thread t1 = new MyThead(m);
		Thread t2 = new MyThead(m);
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		// 睡眠1秒,保证t1先执行
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t2.start();
	}
}

class MyThead extends Thread {

	private MyClass m;

	// 构造方法
	public MyThead(MyClass m) {
		this.m = m;
	}

	public void run() {
		if (Thread.currentThread().getName().equals("t1")) {
			m.doSome();
		}
		if (Thread.currentThread().getName().equals("t2")) {
			m.doOther();
		}
	}

}

class MyClass {
	// synchronized用在了实例方法doSome上
	public synchronized void doSome() {
		System.out.println("doSome start");
		// 睡眠5秒
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("doSome end");
	}

	public void doOther() {
		System.out.println("doOther start");
		System.out.println("doOther end");
	}
}

(2)在(1)的基础上修改代码

class MyClass {
	// synchronized用在了实例方法doSome,  doOther上
	public synchronized void doSome() {
		System.out.println("doSome start");
		// 睡眠5秒
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("doSome end");
	}

	public synchronized  void doOther() {
		System.out.println("doOther start");
		System.out.println("doOther end");
	}
}
/*问doOther方法的执行需要等待doSome方法的结束吗?
 *需要,因为synchronized用在了实例方法doSome, doOther上,表示锁this,
 *this就是指 MyClass m
 *而线程 t1和t2 使用同一个 MyClass对象
doSome start
(5秒后)
doSome end
doOther start
doOther end*/

(3)在(2)的基础上修改代码

        MyClass m1 = new MyClass();
		MyClass m2 = new MyClass();
		Thread t1 = new MyThead(m1);
		Thread t2 = new MyThead(m2);
/*问doOther方法的执行需要等待doSome方法的结束吗?
 *不需要,因为synchronized用在了实例方法doSome, doOther上,表示锁this,
 *this就是指 MyClass m
 *而线程 t1和t2 使用不是同一个 MyClass对象 ,创建2个对象,就是2个对象锁
doSome start
doOther start
doOther end
(5秒后)
doSome end*/		

(4)在(3)的基础上修改代码:

class MyClass {
	// synchronized用在了实例方法doSome,  doOther上
	//把2个方法都改为静态的
	public synchronized static void doSome() {
		System.out.println("doSome start");
		// 睡眠5秒
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("doSome end");
	}

	public synchronized  static  void doOther() {
		System.out.println("doOther start");
		System.out.println("doOther end");
	}
}
/*问doOther方法的执行需要等待doSome方法的结束吗?
 *需要,因为synchronized用在了静态方法doSome和 doOther上,表示类锁,
 *类锁就是指 MyClass  
 *虽然线程 t1和t2 使用不是同一个 MyClass对象 ,创建2个对象, 
 *但是是同一个类,类锁不管创建了几个对象,类锁只有一把
doSome start
(5秒后)
doSome end
doOther start
doOther end*/

2. 总结synchronized的3种写法:

(1)同步代码块

synchronized(线程共享对象){

同步代码块

(2)出现在实例方法上

共享的对象是this,需要同步的代码块是整个方法体

(3)出现在静态方法上

表示类锁

类锁只有一把,区别于对象锁是一个对象一把锁

3. 死锁

不出现异常,也不出现错误,程序一直僵持在哪里, 死锁很难调试

死锁代码要会写:

package 多线程;

public class T3 {

	public static void main(String[] args) {
		Object o1 = new Object();
		Object o2 = new Object();
		//两个线程共享o1,o2
		Thread t1 = new MyThead1(o1, o2);
		Thread t2 = new MyThead1(o1, o2);
		t1.start();
		t2.start();
	}

}
//线程1
class MyThead1 extends Thread {
	Object o1;
	Object o2;
	//构造方法
	public MyThead1(Object o1, Object o2) {
		this.o1 = o1;
		this.o2 = o2;
	}
	public void run() {
		
		synchronized (o1) {//只有外层括号里的代码执行结束,然后o1才会解锁
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized (o2) {
				
			}
		}
	}	
}
//线程2
class MyThead2 extends Thread {
	Object o1;
	Object o2;
	//构造方法
	public MyThead2(Object o1, Object o2) {
		this.o1 = o1;
		this.o2 = o2;
	}
	public void run() {
		synchronized (o2) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized (o1) {
				
			}
		}
	}
}//synchronized在开发中最好不要嵌套使用

4.开发中怎么解决线程安全问题

不是一上来就使用synchronized来选择线程同步,因为synchronized会使程序的执行效率降低,系统的用户吞吐量降低,用户体验不好,在不得已的情况下才会选择线程同步机制

第一种方案:

尽量使用局部变量来代替:实例变量和静态变量

第二种方案:

若必须使用实例变量,那么可以考虑创建多个对象,这样实例变量的内存就不共享了。

第三种方案:

若不能使用局部变量,对象也不能创建多个,就只能使用synchronized了,线程同步机制。

相关