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();}}
- 【Java多线程】多线程死锁
- Java 多线程
- java 多线程
- java多线程
- JAVA多线程
- java多线程
- JAVA多线程
- java多线程
- JAVA 多线程
- Java多线程
- java多线程
- JAVA 多线程
- Java 多线程
- Java 多线程
- java多线程
- Java 多线程
- Java多线程
- java 多线程
- 域名有www与没有www有什么区别?
- 用python去除文件中的空格 || Tab || 回车
- 七夕夜、离别,涵情经河岸
- C# System.IO.FileStream 读取被其他程序打开的文件提示“文件正由另一进程使用,因此该进程无法访问该文件。”
- gun binutils
- Java多线程
- send和recv函数
- android View详解
- ubuntu安装samba进行文件共享
- JS将URL中的UTF-8字符串转成中文字符
- B+树(C++实现)
- 怎么获取网页高度、屏幕高度、滚动高度?
- C#--第三周实验--任务2--输入一个由若干字符组成的字符串,输出其中的大写字母、小写字母、数字和其他字符的个数(控制台应用)
- ASP.NET 成员资格与权限