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

黑马程序员-多线程

2013-09-23 20:26 239 查看
 建立线程的方法:

一:继承Thread类。复写run方法。通过star()开启线程

二:定义类实现Runnable接口。复写run方法。通过Thread类建立线程对象。将Runnable接口的子类作为实际参数传递给Thread类的构造函数。调用Thread类的start方法开启线程并调用Runnable接口的run方法。
class Ticket
{
public void run()
{
}
}
Ticket t = new Ticket();
Thread t1 = new Thread(t);
t1.start();

实现方式的好处:避免了单继承的局限性。

两种方法区别:
继承Thread:线程代码存放在Thread子类run方法中。
实现runnable:线程代码存在接口的子类的run方法中。
线程都有自己默认的名称。Thread—0开始。可以用this.getName()获取。

线程状态图:



安全问题:当多条语句同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完,另一个线程参与进来执行导致共享数据错误。因为在记录数值和赋值之间又有一个线程操作了共享数据,所以真实数值和赋值是不相等的。

解决办法:对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中其他线程不可以参与执行。

同步代码块:synchronnized(对象)
{
需要同步的代码;
}
对象如同锁,持有锁的线程可以在同步中执行。没有持有锁的线程无法获取cpu执行权。

同步的前提:
1.必须要有两个或者两个以上线程。
2.必须是多个线程使用同一个锁。
弊端:多个线程都需要判断锁。较消耗资源。

同步函数:可在函数返回值前加上synchronized修饰。锁为this。
静态同步函数:锁为字节码文件对象。类名.class。该类类型为class。
class Res
{
private String name;
private String sex;
private boolean flag = false;

public synchronized void set(String name,String sex)
{
if(flag)
try{this.wait();}catch(Exception e){}
this.name = name;

this.sex = sex;
flag = true;
this.notify();
}
public synchronized void out()
{
if(!flag)
try{this.wait();}catch(Exception e){}
System.out.println(name+"........"+sex);
flag = false;
this.notify();
}
}

class Input implements Runnable
{
private Res r ;
Input(Res r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
if(x==0)
r.set("mike","man");
else
r.set("丽丽","女女女女女");
x = (x+1)%2;
}
}
}

class Output implements Runnable
{
private Res r ;

Output(Res r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
}

class  InputOutputDemo2
{
public static void main(String[] args)
{
Res r = new Res();

new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
/*
Input in = new Input(r);
Output out = new Output(r);

Thread t1 = new Thread(in);
Thread t2 = new Thread(out);

t1.start();
t2.start();
*/
}
}


单例设计模式的两种方式:
//一,饿汉式:
class Demo
{
private Demo(){}
    private static final Demo d= new Demo();
public static Demo getDemo()
{
return d;
}

}
//二,懒汉式
class Demo
{
  private Demo(){}
  private static Demo d = null;  
  public static Demo getDemo()
  {     
    if(d==null)
    {       
      synchronized(Demo.class)
      {          
      if(d==null)          
       d= new Demo();      
     }
 
    }     
        return d;
 }
} 

死锁:嵌套同步中出现。
class Input implements Runnable
{
private Res r ;
Input(Res r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
synchronized(r)
{

if(r.flag)
try{r.wait();}catch(Exception e){}
if(x==0)
{
r.name="mike";
r.sex="man";
}
else
{
r.name="丽丽";
r.sex = "女女女女女";
}
x = (x+1)%2;
r.flag = true;
r.notify();
}
}
}
}

class Output implements Runnable
{
private Res r ;

Output(Res r)
{
this.r = r;
}
public void run()
{
while(true)
{
synchronized(r)
{
if(!r.flag)
try{r.wait();}catch(Exception e){}
System.out.println(r.name+"...."+r.sex);
r.flag = false;
r.notify();
}
}
}
}

class  InputOutputDemo
{
public static void main(String[] args)
{
Res r = new Res();

Input in = new Input(r);
Output out = new Output(r);

Thread t1 = new Thread(in);
Thread t2 = new Thread(out);

t1.start();
t2.start();
}
}


线程间通讯:其实就是多个线程在操作统一资源,但是操作动作不同。

等待唤醒机制

锁.wait();
锁.notify();唤醒第一个等待的线程。
锁.notifyAll();唤醒所有等待线程。

线程多用while判断。因为if只判断一次。notify唤醒本方线程造成数据错乱。

为什么操作线程的方法要定义在Object类中?
因为这些方法在操作同步中线程时,都必须标识他们所操作的线程持有的锁,只有同一个锁上的被等待的线程可以被同一个锁上的notify唤醒。不可以对不同锁中的线程进行唤醒。锁可以是任意对象。所以定义在Object中。
class ProducerConsumerDemo
{
public static void main(String[] args)
{
Resource r = new Resource();

Producer pro = new Producer(r);
Consumer con = new Consumer(r);

Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);

t1.start();
t2.start();
t3.start();
t4.start();

}
}

/*
对于多个生产者和消费者。
为什么要定义while判断标记。
原因:让被唤醒的线程再一次判断标记。

为什么定义notifyAll,
因为需要唤醒对方线程。
因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。

*/

class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
//  t1    t2
public synchronized void set(String name)
{
while(flag)
try{this.wait();}catch(Exception e){}//t1(放弃资格)  t2(获取资格)//放弃资格就代表释放锁,其他线程可以进入
this.name = name+"--"+count++;

System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag
4000
= true;
this.notifyAll();
}

//  t3   t4
public synchronized void out()
{
while(!flag)
try{wait();}catch(Exception e){}//t3(放弃资格) t4(放弃资格)
System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
flag = false;
this.notifyAll();
}
}

class Producer implements Runnable
{
private Resource res;

Producer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
res.set("+商品+");
}
}
}

class Consumer implements Runnable
{
private Resource res;

Consumer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
res.out();
}
}
}


1.5开始Lock,Condition
java.util.concurrent.locks.*;
import java.util.concurrent.locks.*;

class ProducerConsumerDemo2
{
public static void main(String[] args)
{
Resource r = new Resource();

Producer pro = new Producer(r);
Consumer con = new Consumer(r);

Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);

t1.start();
t2.start();
t3.start();
t4.start();

}
}

/*
JDK1.5 中提供了多线程升级解决方案。
将同步Synchronized替换成现实Lock操作。
将Object中的wait,notify notifyAll,替换了Condition对象。
该对象可以Lock锁 进行获取。
该示例中,实现了本方只唤醒对方操作。

Lock:替代了Synchronized
lock
unlock
newCondition()

Condition:替代了Object wait notify notifyAll
await();
signal();
signalAll();
*/
class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
//  t1    t2
private Lock lock = new ReentrantLock();

private Condition condition_pro = lock.newCondition();
private Condition condition_con = lock.newCondition();

public  void set(String name)throws InterruptedException
{
lock.lock();
try
{
while(flag)
condition_pro.await();//t1,t2
this.name = name+"--"+count++;

System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
condition_con.signal();
}
finally
{
lock.unlock();//释放锁的动作一定要执行。
}
}

//  t3   t4
public  void out()throws InterruptedException
{
lock.lock();
try
{
while(!flag)
condition_con.await();
System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
flag = false;
condition_pro.signal();
}
finally
{
lock.unlock();
}

}
}

class Producer implements Runnable
{
private Resource res;

Producer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
try
{
res.set("+商品+");
}
catch (InterruptedException e)
{
}

}
}
}

class Consumer implements Runnable
{
private Resource res;

Consumer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
try
{
res.out();
}
catch (InterruptedException e)
{
}
}
}
}


如果停止线程?
只有一种,run方法结束。开启多线程运行,运行代码通常是循环结构。只要控制住循环,就能让run方法结束。即线程结束。
特殊情况:当线程处于冻结状态,就不会读到标记。那么线程就不会结束。
class StopThread implements Runnable
{
private boolean flag =true;
public  void run()
{
while(flag)
{

System.out.println(Thread.currentThread().getName()+"....run");
}
}
public void changeFlag()
{
flag = false;
}
}

class  StopThreadDemo
{
public static void main(String[] args)
{
StopThread st = new StopThread();

Thread t1 = new Thread(st);
Thread t2 = new Thread(st);

t1.setDaemon(true);
t2.setDaemon(true);
t1.start();
t2.start();

int num = 0;

while(true)
{
if(num++ == 60)
{
//st.changeFlag();
//t1.interrupt();
//t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"......."+num);
}
System.out.println("over");
}
}


interrupt:冻结状态被强制变成运行状态。
stop:终止线程。

守护线程:t.setDeamon(ture); 后台线程。主线程结束随即结束。

join方法:当A线程执行到了B线程的.join()方法时,A会等待。等待B线程都执行完,A才会执行。
join可以用来临时加入线程执行。
A.start();
A.jion();
B.start();
主线程读到A.jion()时将会释放执行权,使A获取执行权,A执行完毕后,B和主线程开始交替执行。

A.start();
B.start();
A.jion();
主线程读到A.jion()时将会释放执行权,A.B随即获取执行权,A执行完毕后。主线程才能获取执行权。

线程优先级

setPriority();
暂停线程(释放执行权):Thread.yield();

多线程的应用:当某些代码需要被同时执行时。就用代码同时封装。
可用匿名内部的方式对代码进行封装:
new Thread()
{
public void run ()
{
执行代码;
}
}.start();

Runnable r = new Runnable()
{
public void run()
{

}
};
r.start();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: