您的位置:首页 > 职场人生

黑马程序员_JAVA学习日记_JAVA中的多线程补充

2012-08-14 22:38 567 查看
黑马程序员-学习日记

黑马程序员_JAVA学习日记_JAVA中的多线程补充

------- android培训java培训、期待与您交流! ----------

一.多线程的线程类的父类为Thread:
Thread类中的常见方法有:getName();获取线程类的名称,非线程类无法使用该方法获取。线程的默认名字为:Thread-0,1...
非线程类的名字获取方式:通过Thread类中的currentThread()静态方法返回一个线程对象,然后调用getName()方法!
格式:Thread.currentThread().getName();
setName(Stringname)给线程设置名字;Thread(String name)类的构造方法给线程设置名字;
二.线程安全问题代码体现:
比如铁路售票问题:同为100张票,同时被四个窗口售出:
class TicketDemo{
public static void main(String[]args){
Ticket t1=new Ticket();
Ticket t2=new Ticket();
Ticket t3=new Ticket();
Ticket t4=new Ticket();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
public class Ticket extends Thread{
private int ticket=100;
Ticet(){}
public void run(){
while(true){
if(ticket>0){
System.out.println(getName()+"::"+ticket--);
}
}
}
}
这样就会出现安全隐患,会出现每个窗口都有100相同票的情况。
解决办法就是将数据共享;使四个窗口都使用这同100张票。
第一种是加上static使数据共享:但是生命周期过长,每增加一个对象就要创建一次对象。
代码体现:
class TicketDemo{
public static void main(String[]args){
Ticket t1=new Ticket();
Ticket t2=new Ticket();
Ticket t3=new Ticket();
Ticket t4=new Ticket();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
public class Ticket extends Thread{
private static int ticket=100;
Ticet(){}
public void run(){
while(true){
if(ticket>0){
System.out.println(getName()+"::"+ticket--);
}
}
}
}
第二种解决方法:实现Runnable接口,也就是创建线程的第二种方式,实现了数据共享;就是只要创建一个实现了Runnable接口的子类对象就可以。然后通过Thread的构造方法创建一个新的Thread类的来调用它的start()方法,来开启线程的。
class TicketDemoTest implements Runnable{
private int ticket=100;
public TicketDemoTest(){}
public voidrun(){
while(true){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"::"+ticket--);
}
}
}
}
class TicketDemo{
public static void main(String[]agrs){
TicketDemoTest td=new TicketDemoTest();
Thread t1=new Thread(td);
Thread t2=new Thread(td);
Thread t3=new Thread(td);
Thread t4=new Thread(td);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
这时如果在if语句中加入一个Thread类中的sleep()方法后线程就出现了问题。
问题的产生原因:
比如说,卖票到最后1了。这个时候 tickets = 1;
t1,t2,t3,t4都能进到这个地方来。
t1先来,然后,判断,发现1>0,所以t1就进去了。但是,接着t1睡着了。
t2来了,然后,判断,发现1>0,所以t2就进去了。但是,接着t2睡着了。
t3来了,然后,判断,发现1>0,所以t3就进去了。但是,接着t3睡着了。
t4来了,然后,判断,发现1>0,所以t4就进去了。但是,接着t4睡着了。

假如按照顺序醒过来。
t1打印 1。但是tickets=0
t2打印0。但是tickets=-1
t3打印-1。但是tickets=-2
t4打印-2。但是tickets=-3
解决这个问题就要用到同步带块:synchronzed(){code}
代码体现:
class TicketDemoTest implements Runnable{
private int ticket=100;
Object obj=new Object();
public void run(){
while(true){
synchronized(obj){
if(ticket>0){
try{
Thread.sleep(100);
}
catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"::"+ticket--);
}
}
}}
}
这样就解决了安全问题。
这样有了同步代码块相当于有了一个共享的锁!每一次执行就只能有一个线程拿到锁。在同步代码块中锁可以是任意对象。

继承Thread类的代码体现:
class TicketDemoTest extends Thread{
private static int ticket=100;
static Object obj=new Object();
public void run(){//这个地方要不要加静态(为什么不用加static)
while(true){
synchronized(obj){
if(ticket>0){
try{
sleep(100);
}
catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"::"+ticket--);
}
}
}
}
}
这里的代码中锁一定要加静态,保证锁得唯一性,加上static就可以保证锁被共享,所有对象用的是同一个锁。
三:同步方法及线程间的通信:
当一个方法中的方法体被同步代码块所包围起来时这时我们将方法用同步关键字来将方法也同步。
同步方法的锁是this关键字,静态同步方法的锁是类名.class。
同步方法的代码体现:单例设计模式中的懒汉式:其存在安全隐患:改写如下:
class SingeDemo{
private static SingeDemo s=null;
privat SingeDemo(){}
public static synchronized SingeDemo getInstance(){
if(s==null){
s=new SingeDemo;
}
return s;
}
}
产生死锁的原因是:A锁和B锁相互等待。
四:停止线程的方法:
A:run自动结束。
B:stop方法。但是已经过时了。被interrupt替代。
C:可以通过控制循环条件来结束。

五:Thread类中的几个方法:
A:interrupt():中断线程,并抛出一个异常
B:setDaemon(boolean b):设置线程为守护线程。(坦克大战)
C:join():加入线程,具有优先执行权
D:setPriority(int num):设置线程优先级。线程的优先级从1到10,默认为5。
E:toString():返回该线程的字符串表示形式,包括线程名称、优先级和线程组。
F:yield():给其他线程让路,让多个线程间的操作趋近于平衡。

------- android培训java培训、期待与您交流! ----------  详细请查看:http://edu.csdn.net/heima/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: