一、为什么这个是重点?
以后在开发中,我们的项目都是运行在服务器当中,<br /> 而服务器已经将线程的定义,线程对象的创建,线程<br /> 的启动等,都已经实现完了。这些代码我们都不需要<br /> 编写。 最重要的是:你要知道,你编写的程序需要放到一个<br /> 多线程的环境下运行,你更需要关注的是这些数据<br /> 在多线程并发的环境下是否是安全的。(重点:*****)<br />
二、什么时候数据在多线程并发的环境下会存在安全问题呢?
**三个条件**:<br /> 条件1:多线程并发。<br /> 条件2:有共享数据。<br /> 条件3:共享数据有修改的行为。 满足以上3个条件之后,就会存在线程安全问题。<br />
三、怎么解决线程安全问题呢?
当多线程并发的环境下,有共享数据,并且这个数据还会被修改,此时就存在<br /> 线程安全问题,怎么解决这个问题?<br /> 线程排队执行。(不能并发)。<br /> 用排队执行解决线程安全问题。<br /> 这种机制被称为:**线程同步**机制。 专业术语叫做:线程同步,实际上就是线程不能并发了,线程必须排队执行。<br /> <br /> 怎么解决线程安全问题呀?<br /> 使用“线程同步机制”。<br /> <br /> 线程同步就是线程排队了,线程排队了就会牺牲一部分效率,没办法,数据安全<br /> 第一位,只有数据安全了,我们才可以谈效率。数据不安全,没有效率的事儿。<br />
四、说到线程同步这块,涉及到这两个专业术语:
异步编程模型:<br /> 线程t1和线程t2,各自执行各自的,t1不管t2,t2不管t1,<br /> 谁也不需要等谁,这种编程模型叫做:异步编程模型。<br /> 其实就是:多线程并发(效率较高。) 异步就是并发。 同步编程模型:<br /> 线程t1和线程t2,在线程t1执行的时候,必须等待t2线程执行<br /> 结束,或者说在t2线程执行的时候,必须等待t1线程执行结束,<br /> 两个线程之间发生了等待关系,这就是同步编程模型。<br /> 效率较低。线程排队执行。 同步就是排队。
五、synchronized
1.执行原理

六、Java中有三大变量?【重要的内容。】
实例变量:在堆中。静态变量:在方法区。局部变量:在栈中。以上三大变量中:<br /> 局部变量永远都不会存在线程安全问题。<br /> 因为局部变量不共享。(一个线程一个栈。)<br /> 局部变量在栈中。所以局部变量永远都不会共享。<br /> <br /> 实例变量在堆中,堆只有1个。<br /> 静态变量在方法区中,方法区只有1个。<br /> 堆和方法区都是多线程共享的,所以可能存在线程安全问题。局部变量+常量:不会有线程安全问题。<br /> 成员变量:可能会有线程安全问题。
七、如果使用局部变量的话:
建议使用:StringBuilder。<br /> 因为局部变量不存在线程安全问题。选择StringBuilder。<br /> StringBuffer效率比较低。ArrayList是非线程安全的。<br /> Vector是线程安全的。<br /> HashMap HashSet是非线程安全的。<br /> Hashtable是线程安全的。
八、synchronized有三种写法:
第一种:同步代码块<br /> 灵活<br /> synchronized(线程共享对象){<br /> 同步代码块;<br /> } 第二种:在实例方法上使用synchronized<br /> 表示共享对象一定是this<br /> 并且同步代码块是整个方法体。<br /> <br /> 第三种:在静态方法上使用synchronized<br /> 表示找类锁。<br /> 类锁永远只有1把。<br /> 就算创建了100个对象,那类锁也只有一把。<br /> <br /> 对象锁:1个对象1把锁,100个对象100把锁。<br /> 类锁:100个对象,也可能只是1把类锁。
九、synchronized的四种类型(需不需要等)
1.doOther不需要等,因为动态方法doOther没有加synchronized
package synch.Exam;/*doOther不需要等,因为动态方法doOther没有加synchronized */public class Exam01 { public static void main(String[] args) throws InterruptedException { MyClass mc = new MyClass(); Thread t1 = new MyThread(mc); Thread t2 = new MyThread(mc); t1.setName("t1"); t2.setName("t2"); t1.start(); Thread.sleep(1000*5); t2.start(); }}class MyThread extends Thread{ private MyClass mc; public MyThread(MyClass mc) { this.mc = mc; } public void run(){ if(Thread.currentThread().getName().equals("t1")){ mc.doSome(); } if (Thread.currentThread().getName().equals("t2")){ mc.doOther(); } }}class MyClass{ public synchronized void doSome(){ System.out.println("doSome begin"); try { Thread.sleep(1000*10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("doSome over"); } public void doOther(){ System.out.println("doOther begin"); System.out.println("doOther over"); }}
2.doOther需要等,因为动态方法doOther加了synchronized
package synch.Exam02;/*doOther需要等,因为动态方法doOther加了synchronized */public class Exam02 { public static void main(String[] args) throws InterruptedException { MyClass mc = new MyClass(); Thread t1 = new MyThread(mc); Thread t2 = new MyThread(mc); t1.setName("t1"); t2.setName("t2"); t1.start(); Thread.sleep(1000*5); t2.start(); }}class MyThread extends Thread{ private MyClass mc; public MyThread(MyClass mc) { this.mc = mc; } public void run(){ if(Thread.currentThread().getName().equals("t1")){ mc.doSome(); } if (Thread.currentThread().getName().equals("t2")){ mc.doOther(); } }}class MyClass{ public synchronized void doSome(){ System.out.println("doSome begin"); try { Thread.sleep(1000*10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("doSome over"); } public synchronized void doOther(){ System.out.println("doOther begin"); System.out.println("doOther over"); }}
3.doOther不需要等,因为动态方法doOther,new了两个不同的对象
package synch.Exam03;/*doOther不需要等,因为动态方法doOther,new了两个不同的对象 */public class Exam03 { public static void main(String[] args) throws InterruptedException { MyClass mc1 = new MyClass(); MyClass mc2 = new MyClass(); Thread t1 = new MyThread(mc1); Thread t2 = new MyThread(mc2); t1.setName("t1"); t2.setName("t2"); t1.start(); Thread.sleep(1000); t2.start(); }}class MyThread extends Thread{ private MyClass mc; public MyThread(MyClass mc) { this.mc = mc; } public void run(){ if(Thread.currentThread().getName().equals("t1")){ mc.doSome(); } if (Thread.currentThread().getName().equals("t2")){ mc.doOther(); } }}class MyClass{ public synchronized void doSome(){ System.out.println("doSome begin"); try { Thread.sleep(1000*10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("doSome over"); } public synchronized void doOther(){ System.out.println("doOther begin"); System.out.println("doOther over"); }}
4.doOther需要等,因为动态方法doOther变成了静态方法
静态方法是类锁,类锁只有一把
package synch.Exam04;/*doOther需要等,因为动态方法doOther变成了静态方法静态方法是类锁,类锁只有一把 */public class Exam04 { public static void main(String[] args) throws InterruptedException { MyClass mc1 = new MyClass(); MyClass mc2 = new MyClass(); Thread t1 = new MyThread(mc1); Thread t2 = new MyThread(mc2); t1.setName("t1"); t2.setName("t2"); t1.start(); Thread.sleep(1000*5); t2.start(); }}class MyThread extends Thread{ private MyClass mc; public MyThread(MyClass mc) { this.mc = mc; } public void run(){ if(Thread.currentThread().getName().equals("t1")){ mc.doSome(); } if (Thread.currentThread().getName().equals("t2")){ mc.doOther(); } }}class MyClass{ public synchronized static void doSome(){ System.out.println("doSome begin"); try { Thread.sleep(1000*10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("doSome over"); } public synchronized static void doOther(){ System.out.println("doOther begin"); System.out.println("doOther over"); }}
十、死锁
package deadlock;public class DeadLock { public static void main(String[] args) { Object o1 = new Object(); Object o2 = new Object(); Thread t1 = new MyThread1(o1,o2); Thread t2 = new MyThread2(o1,o2); t1.start(); t2.start(); }}class MyThread1 extends Thread{ Object o1; Object o2; public MyThread1(Object o1 , Object o2){ this.o1 = o1; this.o2 = o2; } @Override public void run() { synchronized(o1){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (o2){ } } }}class MyThread2 extends Thread{ Object o1; Object o2; public MyThread2(Object o1 , Object o2){ this.o1 = o1; this.o2 = o2; } @Override public void run() { synchronized(o2){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (o1){ } } }}
十一、我们以后开发中应该怎么解决线程安全问题?
是一上来就选择线程同步吗?synchronized<br /> 不是,synchronized会让程序的执行效率降低,用户体验不好。<br /> 系统的用户吞吐量降低。用户体验差。在不得已的情况下再选择<br /> 线程同步机制。<br /> <br /> 第一种方案:尽量使用局部变量代替“实例变量和静态变量”。
第二种方案:如果必须是实例变量,那么可以考虑创建多个对象,这样<br /> 实例变量的内存就不共享了。(一个线程对应1个对象,100个线程对应100个对象,<br /> 对象不共享,就没有数据安全问题了。)
第三种方案:如果不能使用局部变量,对象也不能创建多个,这个时候<br /> 就只能选择synchronized了。线程同步机制。