码迷,mamicode.com
首页 > 编程语言 > 详细

多线程

时间:2016-08-31 13:45:58      阅读:242      评论:0      收藏:0      [点我收藏+]

标签:

1 多线程概述

进程:正在进行中的程序

 

线程:就是进程中一个负责程序执行的控制单元(执行路径)

 

一个进程中可以多执行路径,称为多线程

 

一个进程中至少要有一个线程

 

开启多个线程是为了同时运行多部分代码

 

每一个线程都有自己运行的内容,这个内容可以称为线程要执行的任务。

 

2多线程创建的方式一

 

创建线程的目的是为了开启一条执行路径,去运行指定的代码和其它代码实现同时运行

 

而运行的指定代码就是这个执行路径的任务

 

java创建的主线程的任务都定义在主函数中

 

而自定义的线程的任务在哪里呢?

Thread类用于描述线程,线程是需要任务的 所以Thread类是对任务的描述

这个任务通过Thread类的run方法来体现。也就是说,run方法就是封装自定义线程运行任务的函数。

 

run方法中定义的就是线程要运行的任务代码

 

开启线程是为了运行指定代码,所以只有要继承Thread类,并复写run方法

 

将任务写在run方法中

/*

 * 如何创建一个线程呢

 *

 * 创建线程方式一:继承Thread

 *

 * 步骤:

 * 1 定义一个类继承Thread

 * 2 覆盖Thread类中的run方法

 * 3 直接创建Thread的子类对象创建线程

 * 4 调用start方法开启线程并调用线程任务的run方法

 *

 *

 *  Thread类的getName是获取线程名称

 *  Thread类的current.getName()是获取当前运行的线程名称

 *  创建线程时 可以通过构造函数为线程赋予自己的名称

 *

 */

 

 

class Task extends Thread

{

 

public void run() {

for(int x=1;x<100;x++)

{

System.out.println(Thread.currentThread().getName()+"数字是"+x+getName());

}

}

 

}

public class ThreadTaskDemo {

    public static void main(String[] args) {

     Task a=new Task();

     Task b=new Task();

     a.start();

     b.start();

     for(int x=1;x<100;x++)

{

     System.out.println(Thread.currentThread().getName()+"数字是"+x);

}

 

}

}

 

 

2 线程的状态

 

被创建 start()

运行  具备CPU的执行权

冻结  sleep(time)  wait() notify()  释放执行权的同时释放执行资格

消亡 stop() run方法结束

临时阻塞 具备执行资格,正在等待执行权

cpu的执行资格:可以被CPU处理,在处理队列中排队

cpu的执行权:正在被CPU处理

 

3创建线程方式二  实现Runnable接口

  /*

   *

   * 实现接口的方式创建线程

   */

public class ThreadDemo2 implements Runnable{

 

public void run() {

for(int x=1;x<100;x++)

{

System.out.println(Thread.currentThread().getName()+"数字是"+x);

}

}

  public static void main(String[] args) {

Thread t1=new Thread(new ThreadDemo2());

Thread t2=new Thread(new ThreadDemo2());

t1.start();

t2.start();

for(int x=1;x<100;x++)

{

System.out.println(Thread.currentThread().getName()+"数字是"+x);

}

}

}

 

 

4 第二种方式创建线程的好处

1 将线程的任务从线程的子类中分离出来,进行单独的封装

按照面向对象的思想将任务封装成对象

 

2 避免了java单独继承的局限性

 

所以这种方式更加常用

 

 

5线程中的安全问题

当多条执行路径共享一个变量时,就会发生不同步的情况

/*

 * 需求:卖票

 *

 */

 class TicketSale implements Runnable

{

private int piao=100;

    

public void salePiao() throws InterruptedException

{  

  while(true)

  {

if(piao>0)

{  

Thread.sleep(500);

System.out.println(piao--+":"+Thread.currentThread().getName());

 

}

  }

}

public void run()

{

try {

salePiao();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

 

 

}

 

 public class TicketDemo

{

public static void main(String[] args) {

 TicketSale task=new TicketSale();

Thread t1=new Thread(task);

Thread t2=new Thread(task);

Thread t3=new Thread(task);

Thread t4=new Thread(task);

t1.start();

t2.start();

t3.start();

t4.start();

}

}

 

 

 

 

 

6解决不同步

就需要用同步代码块来解决

/*

 * 需求:卖票

 *

 */

 class TicketSale implements Runnable

{

private int piao=100;

    Object obj=new Object();

public void salePiao() throws InterruptedException

{  

synchronized (obj)

{

  while(true)

  {

if(piao>0)

{  

Thread.sleep(500);

System.out.println(piao--+":"+Thread.currentThread().getName());

 

}

  }

}

}

public void run()

{

try {

salePiao();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

 

 

}

 

 public class TicketDemo

{

public static void main(String[] args) {

 TicketSale task=new TicketSale();

Thread t1=new Thread(task);

Thread t2=new Thread(task);

Thread t3=new Thread(task);

Thread t4=new Thread(task);

t1.start();

t2.start();

t3.start();

t4.start();

}

}

 

 

7 同步的优点和弊端

优点:解决了不同步的问题

缺点:要判断锁,效率低下

 

要学会使用同步 否则乱使用同步会导致很多的问题出现 而且要学会判断哪里需要同步 哪里不需要同步

 

8同步函数的锁 (this指针)

 

9静态函数的锁(该函数所在的类的字节码对象)

 

10懒汉式涉及的多线程问题

class Single

{

private static Single s=null;

 

private Single(){}

 

public static Single getInstance()

{

if(s==null)

{

synchronized (Single.class)

{

     if(s==null)

      s=new Single();

}

}

return s;

}

 

}

public class Demo {

 

}

 

 

11 死锁示例

class Task implements Runnable

{

 

   

   private boolean flag;

   public Task(boolean flag)

   {

   this.flag=flag;

   }

public void run()

{   

  if(flag)

  {  

  while(true)

  {

  synchronized (Lock.locka)

  {  

  System.out.println("if locka");

synchronized (Lock.lockb)

{

  System.out.println("if lockb");

}

  }

  }

  }

  else

  {

  while(true)

  {

  synchronized (Lock.lockb)

  {

  System.out.println("else lockb");

synchronized (Lock.locka)

{

  System.out.println("else locka");

}

  }

  }

  }

}

 

}

 

 

class Lock

{

 static Object locka=new Object();

 static Object lockb=new Object();

}

 

 

public class Demo

{

public static void main(String[] args) {

 Task task1=new Task(true);

 Task task2=new Task(false);

 

 Thread t1=new Thread(task1);

 Thread t2=new Thread(task2);

 

 t1.start();

 t2.start();

}

 

}

 

 

12 线程间的通信

 

class Resource

{

String name;

String sex;

}

 

class Input implements Runnable

{

Resource r;

Input(Resource r)

{

this.r=r;

}

public void run()

{

 int x=0;

while(true)

{  

synchronized(r)

{   

if(x==0)

{

r.name="君临";

r.sex="";

}

else

{

r.name="大猪";

r.sex="";

    

 

}

x=(x+1)%2;

 

}

}

}

 

}

 

 

class Output implements Runnable

{

Resource r;

Output(Resource r)

{

this.r=r;

}

public void run()

{  

while(true)

{

synchronized (r)

{

System.out.println("姓名"+r.name+"...."+"性别"+r.sex);

}

}

}

 

}

 

public class Demo

{

public static void main(String[] args) {

Resource r=new Resource();

 

Input in=new Input(r);

Output out=new Output(r);

 

Thread t1=new Thread(in);

Thread t2=new Thread(out);

 

t1.start();

t2.start();

 

 

}

}

 

如何使上述的程序可以交替输出呢?

就需要使用等待唤醒机制。

 

 

13 等待唤醒机制

 

/*  等待/唤醒机制

 *

 * 涉及的方法

 *

 * 1 wait 让线程处于冻结状态,被wait的线程会 被存储到线程池中

 * 2 notify 随机叫醒线程池中的一个线程

 * 3 notifyAll 叫醒线程池中的所有线程

 *

 * 这些方法都必须定义在同步中

 *

 * 因为这些方法是用于操作线程状态的方法

 * 必须要明确到底操作的是哪个锁上的线程

 */

 

class Resource

{

String name;

String sex;

boolean flag=false;

}

 

class Input implements Runnable

{

Resource r;

Input(Resource r)

{

this.r=r;

}

public void run()

{

 int x=0;

while(true)

{  

synchronized(r)

{   

if(r.flag)

try 

    {

r.wait();

}

catch (InterruptedException e)

   {

          e.printStackTrace();

}

if(x==0)

{

r.name="君临";

r.sex="";

}

else

{

r.name="大猪";

r.sex="";

}

r.flag=true;

r.notify();

x=(x+1)%2;

 

}

 

}

}

 

}

 

 

class Output implements Runnable

{

Resource r;

Output(Resource r)

{

this.r=r;

}

public void run()

{  

while(true)

{

synchronized (r)

{

if(!r.flag)

{

try {

r.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

else

{

System.out.println("姓名"+r.name+"...."+"性别"+r.sex);

r.flag=false;

r.notify();

}

 

}

}

}

 

}

 

public class Demo

{

public static void main(String[] args) {

Resource r=new Resource();

 

Input in=new Input(r);

Output out=new Output(r);

 

Thread t1=new Thread(in);

Thread t2=new Thread(out);

 

t1.start();

t2.start();

 

 

}

}

 

这个代码是可以优化的

 

 

14 生产者消费者问题

 

/*  等待/唤醒机制

 *

 * 涉及的方法

 *

 * 1 wait 让线程处于冻结状态,被wait的线程会 被存储到线程池中

 * 2 notify 随机叫醒线程池中的一个线程

 * 3 notifyAll 叫醒线程池中的所有线程

 *

 * 这些方法都必须定义在同步中

 *

 * 因为这些方法是用于操作线程状态的方法

 * 必须要明确到底操作的是哪个锁上的线程

 */

 

class Resource

{

String name;

String sex;

private int count=1;

boolean flag=false;

 

public synchronized void set(String name)

{  if(flag)

try {

this.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

 

this.name=name+count;

count++;

System.out.println(Thread.currentThread().getName()+"....生产者......"+this.name);

flag=true;

this.notify();

}

public synchronized void out()

{  

if(!flag)

try {

wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

    System.out.println(Thread.currentThread().getName()+"....消费者..。。。。。...."+this.name);

   flag=false;

   this.notify();

 

}

}

 

class Product implements Runnable

{

Resource r;

Product (Resource r)

{

this.r=r;

}

public void run()

{

while(true)

{  

r.set("北京烤鸭");

}

}

 

}

 

 

class Consumer implements Runnable

{

Resource r;

Consumer(Resource r)

{

this.r=r;

}

public void run()

{  

while(true)

{

      r.out();

}

}

 

}

 

public class Demo

{

public static void main(String[] args) {

Resource r=new Resource();

 

Product p=new Product(r);

Consumer c=new Consumer(r);

 

Thread t1=new Thread(p);

//Thread t2=new Thread(p);

   // Thread t3=new Thread(c);

Thread t4=new Thread(c);

 

t1.start();

//t2.start();

//t3.start();

t4.start();

 

 

}

}

如果是一个消费者 一个生产者 这个程序是可以交替的

但如果是多消费者 多消费者 就会出现问题

/*  等待/唤醒机制

 *

 * 涉及的方法

 *

 * 1 wait 让线程处于冻结状态,被wait的线程会 被存储到线程池中

 * 2 notify 随机叫醒线程池中的一个线程

 * 3 notifyAll 叫醒线程池中的所有线程

 *

 * 这些方法都必须定义在同步中

 *

 * 因为这些方法是用于操作线程状态的方法

 * 必须要明确到底操作的是哪个锁上的线程

 */

 

class Resource

{

String name;

String sex;

private int count=1;

boolean flag=false;

 

public synchronized void set(String name)

{  if(flag)

try {

this.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

 

this.name=name+count;

count++;

System.out.println(Thread.currentThread().getName()+"....生产者......"+this.name);

flag=true;

this.notify();

}

public synchronized void out()

{  

if(!flag)

try {

wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

    System.out.println(Thread.currentThread().getName()+"....消费者..。。。。。...."+this.name);

   flag=false;

   this.notify();

 

}

}

 

class Product implements Runnable

{

Resource r;

Product (Resource r)

{

this.r=r;

}

public void run()

{

while(true)

{  

r.set("北京烤鸭");

}

}

 

}

 

 

class Consumer implements Runnable

{

Resource r;

Consumer(Resource r)

{

this.r=r;

}

public void run()

{  

while(true)

{

      r.out();

}

}

 

}

 

public class Demo

{

public static void main(String[] args) {

Resource r=new Resource();

 

Product p=new Product(r);

Consumer c=new Consumer(r);

 

Thread t1=new Thread(p);

Thread t2=new Thread(p);

    Thread t3=new Thread(c);

Thread t4=new Thread(c);

 

t1.start();

t2.start();

t3.start();

t4.start();

 

 

}

}

 

 

此时可以考虑将if 改成 while  (当程序恢复运行状态,重新判断标志位),此时会发生死锁。 程序都冻结了 这时候应该使用notifyAll()

 

/*  等待/唤醒机制

 *

 * 涉及的方法

 *

 * 1 wait 让线程处于冻结状态,被wait的线程会 被存储到线程池中

 * 2 notify 随机叫醒线程池中的一个线程

 * 3 notifyAll 叫醒线程池中的所有线程

 *

 * 这些方法都必须定义在同步中

 *

 * 因为这些方法是用于操作线程状态的方法

 * 必须要明确到底操作的是哪个锁上的线程

 */

 

class Resource

{

String name;

String sex;

private int count=1;

boolean flag=false;

 

public synchronized void set(String name)

{  while(flag)

try {

this.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

 

this.name=name+count;

count++;

System.out.println(Thread.currentThread().getName()+"....生产者......"+this.name);

flag=true;

this.notifyAll();

}

public synchronized void out()

{  

while(!flag)

try {

wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

    System.out.println(Thread.currentThread().getName()+"....消费者..。。。。。...."+this.name);

   flag=false;

   this.notifyAll();

 

}

}

 

class Product implements Runnable

{

Resource r;

Product (Resource r)

{

this.r=r;

}

public void run()

{

while(true)

{  

r.set("北京烤鸭");

}

}

 

}

 

 

class Consumer implements Runnable

{

Resource r;

Consumer(Resource r)

{

this.r=r;

}

public void run()

{  

while(true)

{

      r.out();

}

}

 

}

 

public class Demo

{

public static void main(String[] args) {

Resource r=new Resource();

 

Product p=new Product(r);

Consumer c=new Consumer(r);

 

Thread t1=new Thread(p);

Thread t2=new Thread(p);

    Thread t3=new Thread(c);

Thread t4=new Thread(c);

 

t1.start();

t2.start();

t3.start();

t4.start();

 

 

}

}

 

总结

 

if判断标记,只有一次,会导致不该运行的线程运行了,出现数据错误

 

While判断标记 解决了线程获取执行权后,是否要运行

 

Notify 只能唤醒一个线程,如果本方唤醒本方 没有意义,而且while 判断标记+Notify会导致死锁

 

notifyAll 可以唤醒对方线程 解决了问题

 

15 JDK5.0新特性

 

以前的同步是隐式操作,JDK5.0新特性是将同步和锁封装成了对象,进行显示操作。同时,可以创建多个监视器,不再使用waitnotify而是awaitsignal

 

 

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

 

class Resource

{

String name;

String sex;

private int count=1;

boolean flag=false;

Lock lock=new ReentrantLock();

Condition con=lock.newCondition();

 

public void set(String name)

{    

lock.lock();

   try

   {

while(flag)

{

    try { con.await();} catch (InterruptedException e) {e.printStackTrace();}

}

    this.name=name+count;

count++;

System.out.println(Thread.currentThread().getName()+"....生产者......"+this.name);

flag=true;

con.signalAll();

   }

   

   finally

   {

   lock.unlock();

   }

}

public void out()

{

lock.lock();

try

   {

while(!flag)

try {con.await();} catch (InterruptedException e) {e.printStackTrace();}

    

 System.out.println(Thread.currentThread().getName()+"....消费者..。。。。。...."+this.name);

     flag=false;

     con.signalAll();

   }

finally

{

lock.unlock();

}

}

 

}

 

class Product implements Runnable

{

Resource r;

Product (Resource r)

{

this.r=r;

}

public void run()

{

while(true)

{  

r.set("北京烤鸭");

}

}

 

}

 

 

class Consumer implements Runnable

{

Resource r;

Consumer(Resource r)

{

this.r=r;

}

public void run()

{  

while(true)

{

      r.out();

}

}

 

}

 

public class Demo

{

public static void main(String[] args) {

Resource r=new Resource();

 

Product p=new Product(r);

Consumer c=new Consumer(r);

 

Thread t1=new Thread(p);

Thread t2=new Thread(p);

    Thread t3=new Thread(c);

Thread t4=new Thread(c);

 

t1.start();

t2.start();

t3.start();

t4.start();

 

 

}

}

只是表示形式变化 思想还是一样的

 

要注意wait方法和notify方法是通过监视器来实现的

 

既然能创建多个监视器对象 那么就可以选择只唤醒对方线程

 

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

 

class Resource

{

String name;

String sex;

private int count=1;

boolean flag=false;

Lock lock=new ReentrantLock();

Condition pro_con=lock.newCondition();

Condition con_con=lock.newCondition();

 

public void set(String name)

{    

lock.lock();

   try

   {

while(flag)

{

    try { pro_con.await();} catch (InterruptedException e) {e.printStackTrace();}

}

    this.name=name+count;

count++;

System.out.println(Thread.currentThread().getName()+"....生产者......"+this.name);

flag=true;

con_con.signalAll();

   }

   

   finally

   {

   lock.unlock();

   }

}

public void out()

{

lock.lock();

try

   {

while(!flag)

try {con_con.await();} catch (InterruptedException e) {e.printStackTrace();}

    

 System.out.println(Thread.currentThread().getName()+"....消费者..。。。。。...."+this.name);

     flag=false;

     pro_con.signalAll();

   }

finally

{

lock.unlock();

}

}

 

}

 

class Product implements Runnable

{

Resource r;

Product (Resource r)

{

this.r=r;

}

public void run()

{

while(true)

{  

r.set("北京烤鸭");

}

}

 

}

 

 

class Consumer implements Runnable

{

Resource r;

Consumer(Resource r)

{

this.r=r;

}

public void run()

{  

while(true)

{

      r.out();

}

}

 

}

 

public class Demo

{

public static void main(String[] args) {

Resource r=new Resource();

 

Product p=new Product(r);

Consumer c=new Consumer(r);

 

Thread t1=new Thread(p);

Thread t2=new Thread(p);

    Thread t3=new Thread(c);

Thread t4=new Thread(c);

 

t1.start();

t2.start();

t3.start();

t4.start();

 

 

}

}

 

这样可以提高效率

 

16

 

sleepwait的区别

Sleep 释放执行资格 不释放锁

Wait 释放执行资格 释放锁

 

在同步中,可能出现多个线程,但是还是会遵循谁拿到锁,谁先运行的原则。

 

 

17 结束线程的方法

1 使用标志位

 

但是如果线程处于冻结状态,无法获取标志位时,就需要使用interrupt方法来破除冻结状态  此时会抛出异常 需要处理

 

2 run方法结束

 

18守护线程

setDeamon()

Thread t2=new Thread();

T2.setDeamon();

如果将一个线程 设置为守护线程,那么它就将成为后台线程,当所有前台线程结束时,这个后台线程无论出于何种状态,也会结束。

 

19join方法

A线程中 如果运行到了 B线程.join()这个方法,那么A线程会等到B线程运行完后才运行   也会抛出异常 需要处理

 

20 线程优先级

一般为

  1 MIN_PRIORITY  

   5 NORM_PRIORITY

  10 MAX_PRIORITY 三个优先级

优先级越高,获取CPU执行权的几率越大。

 

21 yield

Thread.yield()

如果某线程运行到这个方法,那么这个线程会立即释放执行权。

多线程

标签:

原文地址:http://www.cnblogs.com/HJL085/p/5825423.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!