昨天把多线程重新看了一遍,发现自己还是有许多需要理解的地方,现在写一篇总结。
一:利用继承Thread类会出现的问题:
public class SellTicketsThread extends Thread {
private int tickets = 10;
public SellTicketsThread(String name) {
super(name);
}
@Override
public void run() {
while (true) {
if(tickets<=0) break;
synchronized (this) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "卖出第"
+ tickets-- + "张票");
}
}
}
}
}
public class SellTicketsThreadDemo {
public static void main(String[] args) {
SellTicketsThread t1 = new SellTicketsThread("窗口1");
SellTicketsThread t2 = new SellTicketsThread("窗口2");
SellTicketsThread t3 = new SellTicketsThread("窗口3");
t1.start();
t2.start();
t3.start();
}
}
这样的话看上去是用了同步锁锁住了对象,但运行结果却是不符合逻辑的。三个窗口共卖了30张票。
窗口2卖出第10张票
窗口1卖出第10张票
窗口3卖出第10张票
窗口3卖出第9张票
窗口2卖出第9张票
窗口1卖出第9张票
窗口3卖出第8张票
窗口1卖出第8张票
窗口2卖出第8张票
窗口2卖出第7张票
窗口3卖出第7张票
窗口1卖出第7张票
窗口2卖出第6张票
窗口1卖出第6张票
窗口3卖出第6张票
窗口2卖出第5张票
窗口1卖出第5张票
窗口3卖出第5张票
窗口2卖出第4张票
窗口3卖出第4张票
窗口1卖出第4张票
窗口2卖出第3张票
窗口1卖出第3张票
窗口3卖出第3张票
窗口2卖出第2张票
窗口1卖出第2张票
窗口3卖出第2张票
窗口2卖出第1张票
窗口3卖出第1张票
窗口1卖出第1张票
二:利用Runnale接口实现
package SellTickets;
public class SellTicketsThread implements Runnable{
private int tickets = 10;
@Override
public void run() {
while(true){
if(tickets<=0) break;
synchronized(this){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(tickets>0){
System.out.println(Thread.currentThread().getName()+"卖出第"+tickets--+"张票");
}
}
}
}
}
public class SellTicketsThreadDemo {
public static void main(String[] args) {
SellTicketsThread st = new SellTicketsThread();
Thread t1 = new Thread(st,"窗口一");
Thread t2 = new Thread(st,"窗口二");
Thread t3 = new Thread(st,"窗口三");
t1.start();
t2.start();
t3.start();
}
}
窗口一卖出第10张票
窗口一卖出第9张票
窗口一卖出第8张票
窗口三卖出第7张票
窗口二卖出第6张票
窗口二卖出第5张票
窗口三卖出第4张票
窗口三卖出第3张票
窗口三卖出第2张票
窗口三卖出第1张票
这样就不会有问题了,因为三个线程共享的是同一个Runnable开辟的内存.网上几乎都是用的这种方法,能不能不用Runnable接口也能实现这个效果呢??接下来是用Thread实现的两种方式,如有错误之处还请指正.
三:在继承Thread的类中定义静态变量和静态方法,将锁加在静态方法上,让多个线程共享。
public class SellTicketsThread extends Thread {
public SellTicketsThread(String name){
super(name);
}
public SellTicketsThread(){
}
private static int tickets =10;
public synchronized static void take(){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(tickets>0){
System.out.println(Thread.currentThread().getName() + "卖出第"
+ tickets-- + "张票");
}
}
@Override
public void run() {
while(true){
take();
}
}
}
public class SellTicketsThreadDemo {
public static void main(String[] args) {
SellTicketsThread t1 = new SellTicketsThread("窗口1");
SellTicketsThread t2 = new SellTicketsThread("窗口2");
SellTicketsThread t3 = new SellTicketsThread("窗口3");
t1.start();
t2.start();
t3.start();
}
}
窗口1卖出第10张票
窗口1卖出第9张票
窗口3卖出第8张票
窗口3卖出第7张票
窗口3卖出第6张票
窗口2卖出第5张票
窗口2卖出第4张票
窗口3卖出第3张票
窗口1卖出第2张票
窗口1卖出第1张票
四:定义一个锁对象,让多个线程共同用同一个锁,同时将共享变量定义成静态的。
public class SellTicketsThread extends Thread {
Object o =null;
private static int tickets = 10;
public SellTicketsThread(String name,Object o){
super(name);
this.o = o;
}
public SellTicketsThread(){
}
@Override
public void run() {
while(true){
while(true){
if(tickets<=0) break;
synchronized(o){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(tickets>0){
System.out.println(Thread.currentThread().getName()+"卖出第"+tickets--+"张票");
}
}
}
}
}
}
public class SellTicketsThreadDemo {
public static void main(String[] args) {
Object o = new Object();//共同的锁
SellTicketsThread t1 = new SellTicketsThread("窗口1",o);
SellTicketsThread t2 = new SellTicketsThread("窗口2",o);
SellTicketsThread t3 = new SellTicketsThread("窗口3",o);
t1.start();
t2.start();
t3.start();
}
}
窗口1卖出第10张票
窗口1卖出第9张票
窗口1卖出第8张票
窗口3卖出第7张票
窗口3卖出第6张票
窗口3卖出第5张票
窗口3卖出第4张票
窗口2卖出第3张票
窗口2卖出第2张票
窗口2卖出第1张票
还需要注意的是,同步代码块的锁对象是任意对象。所以可以用Object做为一个锁。而同步方法(非静态)的锁对象是 this。静态方法的锁对象是类的字节码文件对象。