Java基础之多线程详解

 

Java多线程是抢占式,谁的优先级高,谁就先执行。

Java使用 java.lang.Thread 类代表线程,所有的线程对象都必须是Thread类或其子类的实例。

Thread类

构造方法:  

public Thread() :分配一个新的线程对象。

public Thread(String name) :分配一个指定名字的新的线程对象。

public Thread(Runnable target) :分配一个带有指定目标新的线程对象。

public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。

常用方法:

public String getName() :获取当前线程名称。

public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。

public void run() :此线程要执行的任务在此处定义代码。

public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。

public static Thread currentThread() :返回对当前正在执行的线程对象的引用。

public  void Join()    终止该线程

创建并启动多线程的步骤

一、使用基类Thread

1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把 run()方法称为线程执行体。

2. 创建Thread子类的实例,即创建了线程对象

3. 调用线程对象的start()方法来启动该线程

public class MyThread extends Thread{
	@Override
	public void run() {
		for( int i = 0;i < 20;i++){
			System.out.println("run"+i);
		}
	}
}
public static void main (String[]args){
	//多线程
	MyThread my1 = new MyThread();
	//my1.run();调用run()方法     单线程
	my1.start();//执行run()方法   多线程   新开一个栈空间
	//main执行
	for(int i  = 0;i < 20;i++){
		System.out.println("main"+i);
	}
}

二、使用Runnable接口

1. 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。

2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。

3. 调用线程对象的start()方法来启动线程

public class DemoRunnableImpl implements Runnable{//步骤一
	@Override
	public void run(){
		for(int i = 0;i < 5;i++){
			System.out.println(Thread.currentThread().getName()+"-->"+i);
		}
	}
}
public static void main (String[] args){
	DemoRunnableImpl demo =new DemoRunnableImpl();//步骤二
	Thread thread= new Thread (demo);
	thread.start();//步骤三
}

三、使用匿名内部类

public static void main(String[] args){
	//线程的父类是Thread
	new  Thread(){
		@Override
		public void run(){
			for(int i = 0;i < 5;i++){
				System.out.println(Thread.currentThread().getName()+"小小张自由");
			}
		}
	}.start();
	//线程的接口是Runnable
	Runnable r = new Runnable(){
		@Override
		public void run(){
			for(int i = 0;i < 5;i++){
				System.out.println(Thread.currentThread().getName()+"身体健康");
			}
		}
	};
	new Thread(r).start();
}

解决线程安全问题

线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无操作,一般来说,这个全局变量是线程安全的。

若有多个线程同时执行写操作,一般都需要考虑线程同步, 否则的话就可能影响线程安全。

synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。

锁对象 可以是任意类型。多个线程对象,要使用同一把锁。在任何时候,最多运行一个线程拥有同步锁,谁拿到锁就进入代码块,其他线程只能等待。

一、同步代码块

//语法格式
synchronized(同步锁){
	//需要同步操作的代码
}
//示例
private int cont = 100;
Object obj = new Object();
@Override
public void run(){
	synchronized(obj){ //被锁住的代码
		while(cont>0){
			//线程休眠10毫秒
			try{
				Thread.sleep(10);
			}catch(Exceptione){
				System.out.println(e.getMessage());
			}
			System.out.println(Thread.currentThread().getName()+"正在抢第"+cont+"票");
			cont--;
		}
	}
}

二、同步方法

将需要同步操作的代码,抽出来。放到一个方法中。Run()方法再调用同步方法

public synchronized void method(){ 
	//可能会产生线程安全问题的代码 
}

三、锁(Lock)机制

     1.在成员位置创建一个ReentrantLock对象

     2.在可能出现安全问题的代码前调用Lock接口中的方法Lock获取锁

     3.在可能出现安全问题的代码后调用Lock接口中的方法unLock释放锁

public class DemoRunnableImpl implements Runnable {
    private int cont = 100;
    Lock lock=new ReentrantLock();//创建一个ReentrantLock对象
    @Override
    public void run() {
        lock.lock();//获取锁
        while (cont > 0) {
            //线程休眠10毫秒
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
            System.out.println(Thread.currentThread().getName() + "正在抢第" + cont + "票");
            cont--;
        }
        lock.unlock();//释放锁
    }
}

线程之间的通信

    多个线程并发执行时, 在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们希望他们有规律的执行, 那么多线程之间需要一些协调通信,以此来帮我们达到多线程共同操作一份数据。

线程状态概述

 等待和唤醒案例——生产者和消费者

        1.顾客和老板线程必须使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行

        2.同步使用的锁对象必须保证唯一

        3.只有锁对象才能能用wait()notify()方法

public static void main(String[] args) {
        Object obj=new Object();//锁对象
        //消费者
        new Thread(){
            @Override
            public void run() {
                while (true){
                    synchronized (obj){  //同步代码段
                        System.out.println("告知老板要的包子种类和数量");
                        try {
                            obj.wait();//线程等待
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //唤醒之后执行的代码
                        System.out.println("包子已经做好了,开吃!");
                    }
                }
            }
        }.start();
        //生产者
        new Thread(){
            @Override
            public void run() {
                while (true){
                    try {
                        Thread.sleep(5000); //花5s做包子
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (obj){ //同步代码段
                        System.out.println("老板5秒钟包子做好了,可以吃包子了!");
                        //做好包子,调用notify方法,唤醒顾客吃包子
                        obj.notify();
                        System.out.println("---------------------");
                    }
                }
            }
        }.start();
    }

 创作不易,如果本篇博客对您有一定的帮助,大家记得留言+点赞哦。

猜你喜欢

转载自blog.csdn.net/promsing/article/details/112408018