Java多线程

来源:互联网 发布:网络借贷法律法规 编辑:程序博客网 时间:2024/05/29 03:56


1、 
线程的概念

现在的操作系统都是都任务的,在同一时刻允许运行多个程序。现在,人们都有单台拥

有多个CPU的计算机,俗称双核或者四核。但是并发执行的进程数目并不是由CPU数目决定的,操作系统将CPU的时间分配给每一个进程,给人一种并行出来的感觉。

多线程程序在较低层次上扩展了多任务的概念,一个程序执行多个任务。通常,每一个任务成为一个线程。能够同时运行一个以上线程的程序称为多线程程序。一个进程中至少有一个线程,在Java中这个线程运行代码存在与main方法中,该线程成为主线程。

多线程和多进程到底有哪些区别呢?本质的区别在于每个进程拥有自己的一整套变量,而线程则共享数据。共享变量使线程直间的通信比进程之间的通信更有效、更容易。此外,在有些操作系统中,与进程相比,线程更“轻量级”,创建、撤销一个线程比启动新进程的开销要小的多。

在实际应用中多线程非常有用。例如:一个浏览器可以同时下载多幅图片。

2、  定义线程

Java中已经定义好了一个Thread类。创建线程呢有两种方法,一种方法是将类声明为

Thread的子类。该子类应重写Thread类的run方法。

      定义线程的步骤:

1、 定义一个类并继承Thread类。

2、 复写Thread类中的run()方法。

3、 调用线程的start()方法;

示例如下:

 

class Thr extends Thread {public void run(){for(int i=0;i<100;i++){System.out.println("Thr run");}}}class ThreadDemo{public static void main(String[] arge){Thr a = new Thr();a.start();for(int i=0;i<100;i++){System.out.println("Hello Java");}}}


为什么要覆盖run方法呢?

      Thread类用于描述一个线程,该类就定义一个功能,用于存储线程要运行的代码,该存储功能就是run方法。

      线程被创建之后有下述四种基本状态执行状态、就绪状态、阻塞状态、消亡状态。运行状态是程序表示线程正在获得处理机而运行;就绪状态是指线程已具备各种执行条件,一旦获得CPU就可以执行的状态;阻塞状态是指线程在执行中因某事件而受阻,比如掉用了Sleep()wait(),处于暂停执行状态。消亡状态是指线程结束不再被运行比如调用stop();

      线程的名字:每个线程有自己默认的名字,但是我们也可以自定义线程名字。默认的名字为直接调用getName()方法,名称为Thread-编号,编号从0开始。自定义名字为在Thread类中有一个构造方法为Thread(String name)方法,我们可以在继承时调用这个父类方法如下:

      class Thr extends Thread

{

             public Thr(Stringname)

             {

                    super(name);

             }

}

创建线程的另一种方法是声明实现Runnable接口的类。该类然后实现run方法。然后可以分配该类的实例,在创建Thread时作为一个参数来传递并启动。1、定义类并实现Runnable接口。2、覆盖Runnable接口中的run()方法。3、通过Thread类建立线程对象。4、将Runnable接口的子类对象作为参数传递给Thread类的构造函数。5、调用Thread类的start()方法开启线程并调用Runnable接口的run()方法。

示例如下:

class Ticket implements Runnable//创建Ticket类并实现Runnable接口{public static int ticket = 100;public void run()//实现Runnable接口的run()方法{while(true){if(ticket>0)System.out.println(Thread.currentThread().getName()+"~~~~~~"+ticket--);}}}class TicketDemo{public static void main(String[] arge){Ticket t = new Ticket();//创建Ticket类对象Thread a1 = new Thread(t);//将Ticket类对象作为参数传入Thread类对象Thread a2 = new Thread(t);a1.start();a2.start();}}

为什么有了Thread类来创建线程还要有Runnable接口来创建线程呢?

在我们创建线程时是继承Thread类并复写run()方法,但是如果我们有一个需要进行多线程的运行的类,但是这个类已经继承过其他类,那么就不能再继承Thread类了,这个时候Runnable的优势就体现出来了,所以这个时候就要用到Runnable接口来实现。

3、多线程的安全问题

      问题原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行一部分,还没执行完,另一条线程参与进来执行,导致共享数据的错误。

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

      Java对于多线程的安全问题提供了专业的解决方式。同步代码块。

Synchronized(对象)

{

      需要被同步的代码;

}

      对象如同锁,持有锁的线程可以在同步中执行。没有持有锁的线程即使获取CPU的执行权,也不能执行,因为锁还未被持有的线程释放。那究竟什么时候需要同步代码呢?

1、 必须要有两个以上或者两个以上的线程。

2、 必须是多个线程使用同一个锁。

那么如何查找代码是否有安全问题呢?

1、 明确哪些代码是多线程运行代码。

2、 明确共享数据。

3、 明确多线程运行代码中哪些语句是操作共享数据的。

4、死锁

所谓死锁是指多个线程在运行过程中因争夺资源而造成的一种僵局,当线程在出于这种

僵局状态时,若无外力作用,它们将无法再向前推进。示例:


class Test implements Runnable{private boolean flag;public Test(boolean flag){this.flag = flag;}public void run(){if(flag){synchronized(MyLock.locka){System.out.println("if locka");synchronized(MyLock.lockb){System.out.println("if lockb");}}}else{synchronized(MyLock.lockb){System.out.println("else lockb");synchronized(MyLock.locka){System.out.println("else locka");}}}}}class MyLock{static Object locka = new Object();static Object lockb = new Object();}class DeathLockTest{public static void main(String[] arge){Thread t1 = new Thread(new Test(true));Thread t2 = new Thread(new Test(false));t1.start();t2.start();}}


      这个程序将很有可能发生死锁。

5、线程间的通信

线程间的通信就是多个线程在操作同一个资源但是操作的动作不同。下面提供一个生产者和消费者的示例里面涉及Lock.lock()Lock.unlock()conditions.await()condition.signal()、的用法,示例如下:

import java.util.concurrent.locks.*;class Resource//创建一个资源类{private String name;private int count = 1;private boolean flag = false;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();this.name = name+"--"+count++;System.out.println(Thread.currentThread().getName()+"………生产者………"+this.name);flag = true;condition_con.signal();} finally{lock.unlock();}}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){}}}}class ProducerConsumerDemo2{public static void main(String[] arge){Resource r = new Resource();Producer pro = new Producer(r);Consumer con = new Consumer(r);Thread t1 = new Thread(pro);Thread t3 = new Thread(pro);Thread t2 = new Thread(con);Thread t4 = new Thread(con);t1.start();t2.start();t3.start();t4.start();}}



 

原创粉丝点击