针对线程的安全问题,可以使用synchronized解决:
public class Outputter { //方法1,用synchronized修饰代码块 // 这个方法锁住的是多线程之间共享的对象 /*public void output(String str){ synchronized (this){ for(int i = 0; i < str.length();i++){ System.out.print(str.charAt(i)); } } }*/ //方法2,用synchronized修饰方法 //这个方法是用synchronized锁住整个方法 public synchronized void output(String str){ for(int i = 0; i < str.length();i++){ System.out.print(str.charAt(i)); } } /** * 需要注意的是,synchronized会造成线程死锁 */ }
public class TraditionalThreadSynchronized { public static void main(String[] args) { final Outputter outputter = new Outputter(); new Thread("Thread1"){ public void run(){ outputter.output("zhangsanlisi "); } }.start(); new Thread("Thread2"){ public void run(){ outputter.output("Chinaese "); } }.start(); new Thread("Thread3"){ public void run(){ outputter.output("American "); } }.start(); new Thread("Thread4"){ public void run(){ outputter.output("abcdefghijklmn "); } }.start(); new Thread("Thread5"){ public void run(){ outputter.output("abcdefghijklmn "); } }.start(); } }
synchronized讲解:
每个锁被称为monitor,有两个队列:就绪队列,阻塞队列。
就绪队列存储了将要获得锁的线程,阻塞队列存储了被阻塞的线程,当一个线程被唤醒notify后,就进入就绪队列,反之被wait后,就进入了阻塞队列。
一个线程执行互斥代码的过程是:
1. 获得同步锁
2. 清空工作内存
3. 从主内存中拷贝对象副本到工作内存
4. 执行代码
5. 刷新主内存
6. 释放同步锁
所以,synchronized保证了线程的有序性和可见性。