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了,线程同步机制。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?