java中的多线程_2

导读:本篇文章讲解 java中的多线程_2,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

一、线程中常用的方法

1.static  Thread  currentThread()得到当前正在运行的的线程对象
2.void  start()启动线程
3.String  getName()返回该线程的名称。
        1.当没有设置线程名称的时候,系统会赋予线程一个默认的名称“Thread-0,Thread-1··”
        2.主线程【主方法的执行线程】的名称默认是”main”
4.void  setName(String name)设置线程名称
例如:

package com.wangxing.test1;

public class Mythread implements Runnable{
	//1.static Thread currentThread()得到当前正在运行的线程对象
	//2.void start() 启动线程
	//3.String getName()返回该线程的名称。
		//1.当没有设置线程名称的时候,系统会赋予线程一个默认的名称“Thread-0,Thread-1......”
		//2.主线程【主方法的执行线程】的名称默认是“main”
	//4.void	setName(String name)设置线程名称
	@Override
	public void run() {
		for(int i=0;i<=50;i++){
			System.out.println(Thread.currentThread().getName()+",i=="+i);
		}
	}
}
package com.wangxing.test1;

public class ThreadMain {
	public static void main(String[] args) {
		//3.String getName()返回该线程的名称。
			//1.当没有设置线程名称的时候,系统会赋予线程一个默认的名称“Thread-0,Thread-1......”
			//2.主线程【主方法的执行线程】的名称默认是“main”
		//4.void	setName(String name)设置线程名称
		//创建目标对象
		Mythread mubiao=new Mythread();
		//将目标对象装换为线程对象
		Thread th1=new Thread(mubiao);
		//设置线程名称
		th1.setName("线程1");
		//得到主方法的线程名称
		System.out.println(Thread.currentThread().getName());		
		th1.start();
	}
}

java中的多线程_2

线程的优先级—就是线程的执行先后
默认情况下所有的优先级都是一样,都是5
我们可以通过
void  setPriority(int  newPriority)更改线程的优先级
1.线程的优先级有10个级别,分别使用整数1~10来表示。数字越大优先级越越高
2.为了方便操作,Java将10个级别有规定成3个级别,分别是最低的优先级,中等的优先级,最高的优先级,并且将这三个级别封装成了静态常量:
        static  int  MAX_PRIORITY线程可以具有的最高优先级。10
        static  int  NORM_PRIORITY分配给线程的默认优先级。  5
        static  int  MIN_PRIORITY线程可以具有的最低优先级。   1
        static  int  getPriority()返回线程的优先级。
3.设置线程的优先级的时候,数字越大优先级越高,数字越大优先级越高,数字越小优先级越低。优先级越高并代表就一定会优先执行,只是被优先执行的几率增大,因此不要试图通过控制线程的优先级,来保证某一个线程,总是第一个执行。
例如:

package com.wangxing.test2;

public class Mythread implements Runnable{
	@Override
	public void run() {
		for(int i=0;i<=50;i++){
			System.out.println(Thread.currentThread().getName()+",i=="+i);
		}
	}
}
package com.wangxing.test2;

public class ThreadMain {
	public static void main(String[] args) {
		//并且将这3个级别封装成了静态常量:
//		static int MAX_PRIORITY 线程可以具有的最高优先级。10
//		static int	MIN_PRIORITY线程可以具有的最低优先级。1
//		static int	NORM_PRIORITY分配给线程的默认优先级。5
//		int	getPriority() 返回线程的优先级。
		//创建目标对象
		Mythread mubiao=new Mythread();
		//将目标对象装换为线程对象
		Thread th1=new Thread(mubiao);
		Thread th2=new Thread(mubiao);
		//设置线程名称
		int priorrity=th1.NORM_PRIORITY;
		th1.setName("线程1");
		th1.setPriority(priorrity);
		System.out.println("线程1的线程优先级"+th1.getPriority());
		th2.setName("线程2");
		th2.setPriority(6);
		System.out.println("线程2的线程优先级"+th2.getPriority());
		th1.start();
		th2.start();
	}
}

java中的多线程_2

 守护线程的相关操作方法
    用户线程—-通常情况之下我们所创建的线程都是普通线程,非守护线程,也叫用户线程。
    守护线程—-也叫精灵线程,当所有用户线程都执行完毕以后,自动结束运行的线程就是守护线程.[共死]
    1.boolean    isDaemon() 测试该线程是否为守护线程。
    2.void    setDaemon(boolean on) 将该线程标记为守护线程用户线程。
    特征:当所有用户线程都执行完毕以后,无论守护线程能否可以继续运行,都要立刻停止运行。
例如:

package com.wangxing.test3;

public class MyThread implements Runnable{
//	守护线程的相关操作方法
//	用户线程----通常情况之下我们所创建的线程都是普通线程,非守护线程,也叫用户线程。
//	守护线程----也叫精灵线程,当所有用户线程都执行完毕以后,自动结束运行的线程就是守护线程.[共死]
//	1.boolean	isDaemon() 测试该线程是否为守护线程。
//	2.void	setDaemon(boolean on) 将该线程标记为守护线程用户线程。
//	特征:当所有用户线程都执行完毕以后,无论守护线程能否可以继续运行,都要立刻停止运行。
	@Override
	public void run() {
		for(int i=0;i<=20;i++){
			System.out.println(Thread.currentThread().getName()+",i=="+i);
		}
	}
}
package com.wangxing.test3;

public class ThreadMain {
	public static void main(String[] args) {
//		守护线程的相关操作方法
//		用户线程----通常情况之下我们所创建的线程都是普通线程,非守护线程,也叫用户线程。
//		守护线程----也叫精灵线程,当所有用户线程都执行完毕以后,自动结束运行的线程就是守护线程.[共死]
//		1.boolean	isDaemon() 测试该线程是否为守护线程。
//		2.void	setDaemon(boolean on) 将该线程标记为守护线程用户线程。
//		特征:当所有用户线程都执行完毕以后,无论守护线程能否可以继续运行,都要立刻停止运行。
		//创建目标对象
		MyThread mubiao=new MyThread();
		//将目标对象装换为线程对象
		Thread th1=new Thread(mubiao);
		Thread th2=new Thread(mubiao);

		th1.setName("线程1");
		//设置线程1为守护线程
		th1.setDaemon(true);
		System.out.println(th1.getName()+","+th1.isDaemon());
		th2.setName("线程2");
		System.out.println(th2.getName()+","+th2.isDaemon());
		th1.start();
		th2.start();
	}
}

java中的多线程_2
static   void    sleep(long millis) 设置线程休眠【暂停】指定的时间【毫秒
void  interrupt() 中断线程休眠【暂停】。会进入异常【InterruptedException】。
例如:上课了小明睡好了,上课后过了5秒老师发现小明睡觉了叫醒了本来应该睡1分钟的小明,小明听了5秒后下课了

package com.wangxing.test4;

public class MyThread extends Thread{
	//static void  sleep(long millis) 设置线程休眠【暂停】指定的时间【毫秒】
	//void  interrupt() 中断线程休眠【暂停】。会进入异常【InterruptedException】	
	@Override
	public void run() {
		String name=Thread.currentThread().getName();
		System.out.println(name+"开始上课!");
		System.out.println(name+"进入梦乡中······");
		//睡了1分钟
		try {
			Thread.sleep(10000);
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println(name+"被叫醒了!");
		System.out.println(name+"开始听课了!");
		//听了5秒后下课
		try {
			Thread.sleep(5000);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("下课了!");
	}	
	
}
package com.wangxing.test4;

public class Main {

	public static void main(String[] args) {
		//创建目标对象
		MyThread mubiao=new MyThread();
		Thread th1=new Thread(mubiao);
		th1.setName("小明");
		System.out.println(Thread.currentThread().getName()+",老师开始上课");
		th1.start();
		//过了5秒发现同学睡觉
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+"老师发现同学睡着了");
		System.out.println(Thread.currentThread().getName()+"老师叫醒了他");
		th1.interrupt();
	}
}

java中的多线程_2
例如:用这个方法写一个闹钟

package com.wangxing.test4;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;

public class naoZhong {

	public static void main(String[] args) throws Exception {
		//设置闹钟
		System.out.print("请设置闹钟:");
		InputStreamReader inToRead=new InputStreamReader(System.in);
		BufferedReader input=new BufferedReader(inToRead);
		String naozhngtime=input.readLine();
		//设置获取当前时间的格式
		SimpleDateFormat geshi=new SimpleDateFormat("HH:mm:ss");
		 
		 boolean flag=true;
		 while(flag){
			 //循环一次的得到新的时间
			 String dangqiantime=geshi.format(new Date());
			 if(naozhngtime.equals(dangqiantime)){
				 System.out.println("闹钟响起!");
				 //当闹钟响起时退出循环
				 flag=false;
			 }
			 //闹钟没响之前每次循环输出一次当前时间
			 System.out.println(dangqiantime);
			 //隔1秒
			 Thread.sleep(1000);
		 }
	}
}

java中的多线程_2

 void  join(long millis)【强制线程执行】等待该线程终止的时间最长为 millis 毫秒
例如:

package com.wangxing.test5;
public class MyThread implements Runnable{
	@Override
	public void run() {
		for (int i = 0; i <= 50; i++) {
			System.out.println(Thread.currentThread().getName()+",i=="+i);
		}
	}
}
package com.wangxing.test5;

public class Mian {
	public static void main(String[] args) {
		MyThread mubiao=new MyThread();
		Thread th1=new Thread(mubiao);
		th1.setName("线程一");
		th1.start();
		
		for(int i=0;i<=20;i++){
			System.out.println(Thread.currentThread().getName()+",i=="+i);
			if(i==10){
				//当i等于10时候,强制执行线程一,不管切换到他没
				try {
					th1.join();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}

java中的多线程_2

二、*****线程的生命周期****** 

1、线程的生命周期就是线程从一开始创建,到run方法执行完毕以后的状态变化。[状态之间的切换]
2、线程的生命周期几种状态【1、新建状态 2、就绪状态 3、运行状态  4.阻塞状态 5.死亡状态】
java中的多线程_2

线程的生命周期描述
1.新建状态:通过new的方式创建出线程对象,此时线程就进入到创建状态【新建状态】。
         新建状态的线程是不能运行。
         新建状态的线程调用start方法,进入就绪状态
2.就绪状态:线程具备运行能力,只差操作系统【CPU】分配给他运行时间片【万事具备,只欠时间片】
        得到操作系统【CPU】分配给他运行时间片,此时开始执行run方法,进入运行状态。
3.运行状态:线程运行run方法。
        回到就绪状态:
        1.操作系统【CPU】分配给他运行时间片使用完毕,回到就绪状态。
        进入阻塞状态
        1.运行状态的线程执行了sleep方法,进入阻塞状态。
        2.运行状态的线程执行了wait方法,进入阻塞状态。
        3.运行状态的线程执行输入/输出动作,进入阻塞状态。
        ……
        进入死亡状态
        1.运行状态的线程run方法执行完毕,进入死亡状态。
        2.运行状态的线程调用stop()/destroy() ,进入死亡状态。
4.阻塞状态:线程暂停运行
        回到运行状态
        阻塞状态中的线程,结束了造成阻塞的原因,此时线程进入就绪状态,得到操作系统【CPU】分配给他运行时间片就可以进入运行状态。
        运行状态进入阻塞状态原因:
        1.运行状态的线程执行了sleep方法,进入阻塞状态,休眠时间结束/interrupt,进入就绪状态
        2.运行状态的线程执行了wait方法,进入阻塞状态,调用notify/notifyAll,进入就绪状态
        3.运行状态的线程执行输入/输出动作,进入阻塞状态,输入/输出结束,进入就绪状态
5.死亡状态:线程运行结束,释放运行资源。
        死亡状态的线程是不能运行,除非再一次使用strat方法重新启动运行。    

三.线程安全 

卖票实例:
package com.wangxing.test6;
public class MyThread1 implements Runnable{
    private  int  piao=5;
    @Override
    public void run() {
        //得到线程名称
        String name=Thread.currentThread().getName();
        //持续买票
        boolean flag=true;
        while(flag){
            //判断有没有可卖的票
            if(piao>0){
                //收钱–找钱–打印票
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(name+”,卖出1张票,还剩”+(–piao)+”张”);
            }else{
                flag=false;
            }
        }
    }
}

package com.wangxing.test6;
public class Main1 {

    public static void main(String[] args) {
        MyThread1  my=new MyThread1();
        Thread  th1=new Thread(my);
        Thread  th2=new Thread(my);
        Thread  th3=new Thread(my);
        th1.setName(“窗口1”);
        th2.setName(“窗口2”);
        th3.setName(“窗口3”);
        th1.start();
        th2.start();
        th3.start();
    }
}

运行结果:
窗口3,卖出1张票,还剩3张
窗口1,卖出1张票,还剩4张
窗口2,卖出1张票,还剩2张
窗口2,卖出1张票,还剩1张
窗口1,卖出1张票,还剩0张
窗口3,卖出1张票,还剩-1张

        分析结果:当窗口1卖最后一张票的时候,在收钱打印票的时候,还没有来得及对票数进行减1之前,线程就切换给了窗口3,窗口3认为还有一张票,窗口3就收钱收钱打印票的时候,还没有来得及对票数进行减1之前,线程有切换给了窗口1,窗口1就对票数进减1,完成以后线程切换给窗口3,窗口3对对票数进行减1此时就得到-1这个值。
经过上面运行程序的分析,我得到的结果是:
当多条线程,同时访问同一个资源的时候,会产生数据不一致的错误情况。
为了解决这种数据不一致的错误情况,我们才学习线程同步。
 什么是线程同步/线程安全?
        线程同步也叫线程安全,当多条线程,同时访问同一个资源的时候,每一次只能由多条线程中的其中一条访问公共资源,当这一条线程访问公共资源的时候,其他的线程都处于等待状态,不能访问公共资源,当这一条线程访问完了公共资源以后,其他线程中的一条线程才能访问资源,剩下的线程继续等待,等待当前线程访问结束,实现这个过程就是线程同步。【排队访问资源】
线程同步/线程安全的实现方式有几种,分别是什么,有什么区别?
1.Synchronized关键字 【同步代码块/同步方法】
        1.同步代码块
             格式:synchronized(同步对象){

              }

package com.wangxing.test6;

public class buyPiao implements Runnable {
	int piao = 50;
	// 持续卖票
	boolean flag = true;
	@Override
	public void run() {
		while (flag) {
			synchronized (this) {
				if (piao > 0) {
					// 收钱--找钱--打印票的时间
					/*try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}*/
					System.out.println(Thread.currentThread().getName() + ",买了一张票,剩余了" + --piao + "张");
				} else {
					flag = false;
				}
			}
		}
	}
}
package com.wangxing.test6;

import com.wangxing.test5.MyThread;
public class Main {
	public static void main(String args[]){
		buyPiao mubiao=new buyPiao();
		Thread th1=new Thread(mubiao);
		Thread th2=new Thread(mubiao);
		Thread th3=new Thread(mubiao);
		th1.setName("窗口1");
		th2.setName("窗口2");
		th3.setName("窗口3");
		th1.start();
		th2.start();
		th3.start();
	}
}

java中的多线程_2

    同步代码块虽然可以实现买票的效果,但是它在使用的时候,需要设置一个同步对象,由于我们很多时候都不知道这个同步对象应该是谁,容易写错,造成死锁的情况。正是因为这个缺点,我们很少使用同步代码块来实现线程同步。
        2.同步方法
                同步方法的定义格式: 访问限制修饰符  synchronized  方法返回值类型 方法名称(){

                }
例如:

package com.wangxing.test6;

public class buyPiao implements Runnable {
	int piao = 50;
	// 持续卖票
	boolean flag = true;

	@Override
	public synchronized void run() {
		while (flag) {
			//synchronized (this) {
				if (piao > 0) {
					// 收钱--找钱--打印票的时间
					/*try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}*/
					System.out.println(Thread.currentThread().getName() + ",买了一张票,剩余了" + --piao + "张");
				} else {
					flag = false;
				}
			//}
		}
	}
}

2.通过Lock接口
public interface Lock
        常用的接口方法
        void    lock() 获得锁。 
        void    unlock() 释放锁。
        由于上面的锁方法是Lock接口,我们要使用就得先创建出Lock接口对象,由于Lock是个接口不能new ,我们就得使用它的子类来创建对象。
        Lock接口的子类ReentrantLock
例如:

package com.wangxing.test6;

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

public class buyPiao implements Runnable {
	int piao = 50;
	// 持续卖票
	boolean flag = true;
	//定义Lock对象
	private Lock mylock=new ReentrantLock();
	@Override
	public  void run() {
		while (flag) {
			//synchronized (this) {
			//获得锁
			mylock.lock();
				if (piao > 0) {
					// 收钱--找钱--打印票的时间
					/*try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}*/
					System.out.println(Thread.currentThread().getName() + ",买了一张票,剩余了" + --piao + "张");
				} else {
					flag = false;
				}
			//}
			//释放锁
				mylock.unlock();
		}
	}
}

******Synchronized关键字与Lock接口的区别?*****
    synchronized:
        1.synchronized关键字
        2.自动锁定资源,不灵活
        3.异常时会自动释放锁
        4.不能中断锁,必须等待线程执行完成释放锁。
    Lock:
        1.Lock接口
        2.手动锁定资源,灵活
        3.异常时不会自动释放锁,所以需要在finally中实现释放锁
        4.可以中断锁

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/79831.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!