线程基础->->深入理解java多线程
1.多线程操作同一数据
* 多线程并发操作同一数据时, 就有可能出现线程安全问题* 使用同步技术可以解决这种问题, 把操作数据的代码进行同步, 不要多个线程一起操作
例子:火车站卖票问题,四个线程同时卖100张票
package 测试区;
public class Demo3_Ticket {
/**
* 需求:铁路售票,一共100张,通过四个窗口卖完.
*/
public static void main(String[] args) {
new Ticket().start();
new Ticket().start();
new Ticket().start();
new Ticket().start();
}
}
class Ticket extends Thread {
private static int ticket = 100; //这里注意要加静态
//private static Object obj = new Object(); //如果用引用数据类型成员变量当作锁对象,必须是静态的
public void run() {
while(true) {
{
if(ticket <= 0) {
break;
}
try {
Thread.sleep(10); //线程1睡,线程2睡,线程3睡,线程4睡,用来模拟中间的其他操作,表示间歇
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + "...这是第" + ticket-- + "号票");
}
}
}
}
输出结果:
为什么会卖-1张票呢?原因是因为这里的线程方法并不是同步的,就是有可能在线程2进入while循环且快执行到ticket–这个一步时,线程1抢先一步将ticket减到0,这样线程2并不会退出,而是继续执行,因此就会产生-1这样的结果。为了解决这一问题,我们可以采用同步代码块的方法。注意这里的锁对象不能是this对象,因为每个线程都有一个this,而他们并不一样,也不能在run方法中创建对象同步,应为每个线程里面的对象也是独立的,但是可以用静态对象来解决这个问题。推荐使用字节码对象,例如上面的Ticket.class。
加上了以后输出就正常了:
2. 多线程死锁
当线程的代码块同步嵌套,就可能会发生锁死的情况
例子:假设有两个人分别叫做thread1,和thread2,他们去抢左筷子和有筷子,但是只有当都拿到了一双筷子才能吃一口饭,且只有一方吃过一口饭后才能把筷子交给对方。这样当两个人一人拿到一双筷子后就会产生一种悖论,对应到计算机中就是线程的锁死。
package 测试区;
public class Demo5_DeadLock {
/**
* @param args
*/
private static String s1 = "筷子左";
private static String s2 = "筷子右";
public static void main(String[] args) {
new Thread() {
public void run() {
while(true) {
synchronized(s1) {
System.out.println(getName() + "...获取" + s1 + "等待" + s2);
synchronized(s2) {
System.out.println(getName() + "...拿到" + s2 + "开吃");
}
}
}
}
}.start();
new Thread() {
public void run() {
while(true) {
synchronized(s2) {
System.out.println(getName() + "...获取" + s2 + "等待" + s1);
synchronized(s1) {
System.out.println(getName() + "...拿到" + s1 + "开吃");
}
}
}
}
}.start();
}
}
输出结果
这里前面几句是因为Thread-0启动的比较早,但是当Thread-1启动后,双方互不释放信号,这样就会发生死锁,进程停止,正常情况下,程序会一直进行。当然也会出现互相按顺序执行的情况机率非常小。
所以,不要使用有嵌套的同步
3.回顾常用类线程安全
①Vector 是线程安全的,ArrayList 是线程不安全的
同理查看源码可知,
②StringBuffer线程安全,StringBuilder线程不安全
③HashTable 线程安全,HashMap线程不安全
但是没关系,Collection中有三个对应的方法可以把线程不安全的变成线程安全的。