java基础—7.多线程

来源:互联网 发布:vb自动处理网页弹框 编辑:程序博客网 时间:2024/06/06 05:57

一、概念及理解

|--进程:正在进行中的程序(直译)。
|--线程:进程中一个负责程序执行的控制单元(执行路径)。
1、一个进程中可以有多个执行路径,称之为多线程。
2、一个进程中至少要有一个线程。3、开启多个线程是为了同时运行多部分代码,每一个线程都有自己运行的内容,这个内容可以称为线程要执行的任务。
|--多线程相对单线程的特点
|--多线程的好处:解决了多部分代码同时运行的问题。|--多线程的弊端:线程太多,会导致效率的降低。
其实,多个应用程序同时执行都是CPU在做着快速的切换完成的。这个切换是随机的。CPU的切换是需要花费时间的,从而导致了效率的降低。JVM启动时启动了多条线程,至少有两个线程可以分析的出来:1.执行main函数的线程,该线程的任务代码都定义在main函数中。2.负责垃圾回收的线程。

二、线程创建方法

|--继承Thread类:直接继承Thread类,必需实现run()方法;
Thead_Demo t = new Thread_Demo();t.start();
|--实现Runnable接口:因为java是单继承,使用接口增强了代码的扩展性,必需实现run()方法,一般用此方法:
Runnable_Demo rd = new Runnable_Demo();Thread t   =  new Thread(rd);r.start();

|--卖票举例

package threadTest;/** *买票线程的思考: *1.一个资源,多个线程执行,票和买票窗口是不同类别,分别建立Ticket类、TicWindow类; *2.由于是多个线程,所以要考虑到安全问题,用同步机制; *3.一个资源,多个操作,属于资源共享情况,有两种方法可以解决,这里用静态方法;(还有一种可以传递统一对象) *  */public class TicketTest {public static void main(String[] args) {for (int i = 1; i < 4; i++) {new Thread(new TicWindow(String.valueOf(i))).start();}}}//定义票的资源,要用到的资源及方法定义成静态class Ticket{private static  int tic = 100;public static int sellTic(){//卖票的方法return tic--;}public static int getTic(){return tic;}public static void setTic(int tic) {//设置多少张票Ticket.tic = tic;}}//定义买票窗口类,class TicWindow implements Runnable {String name;public void run(){while(true){//同步代码块保证线程安全synchronized(TicWindow.class){//判断是否有票,有则买,没有就退出线程if(Ticket.getTic()>0)try {Thread.sleep(50);System.out.println(Thread.currentThread().getName()+"第"+name+"窗口"+"卖出第 "+Ticket.sellTic()+" 张票");} catch (InterruptedException e) {e.printStackTrace();}elsebreak;}}}TicWindow(String name){this.name=name;}}

三、线程状态及线程常用方法

|--线程状态
|--运行start()
|--冻结wait()和sleep(),放弃了CPU的执行权|--等待有cpu的执行权,但还没执行|--停止run()方法结束,通过建立“生命周期标记”来控制run循环结束

|--线程常用方法
|--interrupt()     清除中断状态(wait()/sleep()/join())|--join()               暂停其它线程,执行指定线程|--yield()             暂停当前正在执行的线程对象,并执行其他线程。|--setPriority()   更改线程的优先级(一般用0、5、10级)|--setDaemon() 指定为守护线程,当所有线程都为守护线程时,程序停止|--currentThread() 返回对当前正在执行的线程对象的引用|--toString()        返回该线程的字符串表示形式,包括线程名称、优先级和线程组。

四、线程的安全(同步机制)

|--同步的两种方法:
|--Lock、Condition
JDK1.5升级后的新特性,Lock取代了 synchronized,Condition取代了wait/notify/notifyAll,让程序等待唤醒机制更灵活
|--synchronized
|--synchronized(obj){}  代码块 
|--好处:解决了线程的安全问题
|--缺点:判断锁会耗费资源,线程较多时,影响程序运行效率|--前提:需要有两个以上线程才上锁
|--synchronized函数:锁对象默认是this对象;如果是静态函数,锁对象默认是 类名.class
|--同步注意的两个点
|--死锁:两个不同的锁相嵌套,相互关联,相互不放锁,使线程停止运行的情况,用于程序的同步
|--同锁:针对线程之间的通信,必需用相同的锁

五、等待唤醒机制

等待唤醒机制其实是通过一个标记,合理运用wait() 和notify()/notifyAll()方法控制线程,最终达到控制CPU执行顺序的目的。等待的线程都存在于线程池中。notify()唤醒第一个线程,notifyAll()唤醒全部。
|--方法一  synchronizedwait()和notify()定义在上帝类Object中的原因是,任意对象都可以作当作锁的对象(监视器),根据面向对象的向上转型的思维,定义上帝类Object类是通用的……
只有同一个锁上的被等待线程,可以被同一个锁上notify()唤醒
|--方法二   Lock、Condition
Lock类要手动加锁和关锁,一个锁上可以设置多个监视器

六、多线程之间的通信

|--思路 : 针对共同资源进行操作,一般模式:
class Res{//to do something}class T1 implements Runnable{Res r;T1(Res r){this.r =r;}public void run{}}class T2 implements Runnable{Res r;T2(Res r){this.r =r;}public void run{}}//然后在main方法中对同一对象操作public static void main(String[] args ){Res r = new Res();T1   t1 = new T1(r);T2   t2 = new T2(r);} 
|--线程通信的安全
不同线程之间用同一锁,否则出错。可以统一用资源对象。
package threadTest;/** *多线程之间通信考虑的问题: *1.资源共享:两种方法,static静态处理,IO流装饰类模式; *2.线程安全:synchronized,Lock,这里运用synchronized;  *3.线程运行次序,即等待唤醒机制:运用wait()/notify(); *注意: *1.wait()抛出InterruptedException,需要处理; *2.wait()/notify()是定义在“上帝类中”,同一锁调用,如 p.wait();  *步骤:  *1.建立资源类,操作类1、操作类2、操作类3…………操作类中new资源对象,并让对象一致; *2.多线程考虑安全问题,用synchronized函数; *3.主函数中建立对象,开启线程; *  */public class InputOutputDemo {public static void main(String[] args) {Person p = new Person();Input in = new Input(p);Output out = new Output(p);new Thread(in).start();new Thread(out).start();//以上四句,可以简写成以下//new Thread(new Input(p)).start();//new Thread(new Output(p)).start();}}//1.定义资源类Personclass Person{private String name ;private String sex ;private boolean flag = false;//用于控制等待与唤醒的标记public synchronized void set (String name ,String sex){if(this.flag){try {this.wait();}catch (InterruptedException e) {e.printStackTrace();}}this.name= name;this.sex = sex;this.flag = true;this.notify();}public synchronized void out(){if(!this.flag){try {this.wait();}catch (InterruptedException e) {e.printStackTrace();}}System.out.println(this.name+"…………"+this.sex);this.flag = false;this.notify();}}//2.定义输入类Inputclass Input implements Runnable{//定义资源对象,类似于IO流的装饰类Person p;int x =0;public void run() {while (true) {if (x == 0)p.set("mike", "man");else p.set("丽丽", "女女女女女");x = (x + 1) % 2;}}Input(Person p){this.p = p;}}//3.定义输出类Output类class Output implements Runnable{Person p ;public void run() {while(true){p.out();}}Output(Person p){this.p = p;}}
|--等待唤醒机制
两个方法(synchronezied、lock),考虑到效率问题一般用lock/Condition方法,lock/Conditions可以更加具体控制、更加针对控制同一类操作线程。
package threadTest;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/** *多线程间通信测试:多个生产者同时生产,多个消费都同时消费 *思考:多线程通信目前有两种方法: *1.static方法, *2.类似于IO流的装饰模式; *ps.static在内存中存在周期过长,对内存不友好,一般用装饰模式,即建立资源统一操作 *步骤: *1.建立资源类,操作类1、操作类2、操作类3…………操作类中new资源对象,并让对象一致; *2.多线程考虑安全问题,等待唤醒优先用Lock/Condition方法,不同操作类用不同锁; *3.主函数中建立对象,开启线程; *  */public class ProducerConsumerDemo {public static void main(String[] args) {Resource r = new Resource();new Thread(new Producer(r)).start();new Thread(new Producer(r)).start();new Thread(new Consumer(r)).start();new Thread(new Consumer(r)).start();}}//1.创建资源类Resourceclass Resource{private int count=0;private String name ;private boolean flag=false;private Lock lock = new ReentrantLock();//父类引用指向子类对象private Condition condition_pro = lock.newCondition();//生产监视private Condition condition_con = lock.newCondition();//消费监视//生产方式,用Lock/Condition方法保证线程同步及等待唤醒public void set(String name){lock.lock();//关锁try {while(flag)condition_pro.await();this.name = name;this.count ++;Thread.sleep(50);System.out.println(Thread.currentThread().getName()+"……生产………"+this.name+this.count);flag = true;condition_con.signalAll();} catch (Exception e) {e.printStackTrace();}finally{lock.unlock();//开锁,关闭资源的语句定义在finally中}}//消费方式,用Lock/Condition方法保证线程同步及等待唤醒public  void out(){lock.lock();//关锁try {while(!flag)condition_con.await();//消费都等待Thread.sleep(50);System.out.println(Thread.currentThread().getName()+"……消费…………………"+this.name+this.count);flag = false;condition_pro.signalAll();//唤醒生产者的线程} catch (Exception e) {e.printStackTrace();}finally{lock.unlock();//开锁,关闭资源的语句定义在finally中}}}//2.创建生产者Producerclass Producer implements Runnable{Resource r;public void run(){while(true){r.set("箱子");}}Producer(Resource r){this.r = r;}}//创建消费者Consumerclass Consumer implements Runnable{Resource r;public void run(){while(true){r.out();}}Consumer(Resource r){this.r = r;}}

0 0
原创粉丝点击