javase--多线程总结。

多线程

1.概述
进程:是一个正在执行中的程序,每个进程执行的有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。
线程:就是进程中一个独立的控制单元。线程控制着进程的执行。
一个进程至少有一个线程。例如,jvm启动的时候会有一个进程java.exe。该进程至少一个线程负责java运行程序的执行,而且这个线程的运行的代码存在于main方法中,这个线程称为主线程。
拓展:实际上jvm不仅启动一个线程,还有负责垃圾回收的线程。
2.创建线程
创建线程有两种方法:
继承Thread类创建线程:
步骤:

  1. 定义类继承Thread。
  2. 复写Thread类中的run方法。
  3. 调用线程的start方法。(该方法两个作用:1.启动该线程。2.调用run方法。)
class Demo extends Thread{
		public void run{
			for(int i=0;i<160;i++){
				system.out.println("no");
			}
		}
}
class Demo{
	pubilc static void main(String[] args){
		Demo d=new Demo();
		d.start();
		for(int i=0;i<160;i++){
				system.out.println("yes");
			}
	}
}

其实,为了更加明确是哪个线程,可以调用Thread.currentthread.getName()方法。
以上结果:yes和no交替执行。
实现Runable接口
步骤:

  1. 定义实现Runable接口。
  2. 覆盖Runable接口中的run方法。
  3. 通过Thread类创建对象。
  4. 将Runable接口的子类对象传递给Thread类的构造函数。
  5. 调用Thread类的start方法开启线程并调用runable接口子类的run方法。
    :多人售票:
package 平常练习;

public class Demo {
    public static void main(String[] args) {
        Tickets t = new Tickets();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        t1.start();
        t2.start();
        t3.start();
    }

}

class Tickets implements Runnable {
    private int tickets = 100;
    Object obj = new Object();

    public void run() {
        while (true) {
            synchronized (obj) {
                if (tickets > 0) {
                    try {
                        Thread.sleep(10);
                    } 
                    catch (Exception e) {
                    }
                    System.out.println(Thread.currentThread().getName() + "sale" + tickets--);
                }
            }
        }
    }
}

上述代码出现了sleep方法和Synchronized下面将具体说明。
Synchronized
java对多线程的安全问题提供了专业的解决模式
同步代码块

Synchronized(对象){
		需要同步的代码
}

对象如同锁,持有锁的线程可以在同步中执行。
没有锁的线程即使获取cpu的执行权也进不去,因为没有获取锁。

*同步的前提

1. 必须有两个或者两个以上线程。
2. 必须是多个线程使用同一个锁。
3. 必须保证同步中只能有一个线程在执行。
(好处:解决了多线程的安全问题。弊端:多线程需要判断锁,较为消耗资源。)
注意:同步函数使用的锁是this。静态方法的锁是该方法所在类的字节码文件对象,即类名.class。
提到了锁,想起前面的单例设计模式,懒汉式加锁有效解决了多线程的安全问题。
饿汉式:

class Single {
    private Single(){}
    private static Single s=new Single();
    public static Single getInstance(){
        return s;
    }
}

懒汉式:

class Single{
    private static volatile Single s=null;//(volatile防止指令重排序,现在我不是很懂。)
    private Single();
    public static Single getInstance(){
        if(s==null){
            synchronized (Single.class){
                if(s==null)
                    S=new Single();
            }//双重判断能有效提高效率。
        }
    }
    return s;
}

死锁
两个或两个以上线程都在等待对方释放资源,自己才能执行,所以都会进入阻塞状态。
线程的多种状态

在这里插入图片描述
sleep(时间):将当前线程冻结一段时间。
wait():使当前线程冻结,通常与notify()一起使用。
notify():唤醒当前冻结的进程。
notifyAll():唤醒线程池中所有冻结的线程。
注意:后三个方法使用时必须具有锁的时候使用。也就是说,同一个锁上被等待的线程可以被同一个锁的notify唤醒,等待和唤醒必须是同一个锁。
在JDK1.5中提供了多线程升级解决方案:

  • 将同步Synchronized替换成现实lock操作。
  • 将Object类中的wait,notify,notifyAll,替换了condition对象。该对象可以Lock锁进行获取。
  • 该示例中,实现类本方只唤醒对方的操作。
    例:生产者,消费者
package 平常练习;


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Demo1{
    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();
    }
}
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){

            }
        }
    }
}

停止线程
stop方法已经过时,如何停止线程?
只有一种——run方法结束。开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,也就是线程结束。
特殊情况:当线程处于了冻结状态,就不会读取到标记,那么线程就不会结束,当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除,这样就可以操作标记让线程结束。thread类提供了该方法——interrupt();
例:

package 平常练习;

public class StopThreadDemo {
    public static void main(String[] args) {
        StopThread st=new StopThread();
        Thread t1=new Thread(st);
        Thread t2=new Thread(st);
        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");
    }
}
class StopThread implements Runnable{
    private boolean flag=true;
    public synchronized void run()
    {
        while(flag){
            try{
                wait();
            }
            catch(InterruptedException e){
                System.out.println(Thread.currentThread().getName()+"...Exception");
            }
            System.out.println(Thread.currentThread().getName()+"....run");
        }
    }
    public void changeFlag(){
        flag=false;
    }
}

守护线程
线程.setDaemon(boolean),当bollean为true时,该线程为守护线程,注意该方法必须在线程开启前调用。
守护线程的特点:当正在运行的线程都是守护线程时,java虚拟机退出。
join方法
当A线程执行了B线程的join方法时,A就会等待,等B线程都执行完,A才会执行,join可以用来加入线程执行。
yeild和设置线程优先级
.yeild方法:可以临时是放线程执行权,,使多个线程平均一下输出频率,交替更换线程。
设置优先级:.setPriority(Thread.MAX-PRIORITY);设为最大优先级,获得最大频率。

发布了14 篇原创文章 · 获赞 0 · 访问量 308
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 深蓝海洋 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览