java基础16

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

1.线程中常用的方法

        1.static Thread currentThread()得到当前正在运行的线程对象

        2.void start() 启动线程
        3.String getName()返回该线程的名称。
           1.当没有设置线程名称的时候,系统会赋予线程一个默认的名称“Thread-0,Thread-1......”
           2.主线程【主方法的执行线程】的名称默认是“main”
         4.void    setName(String name)设置线程名称

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

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

        static void    sleep(long millis) 设置线程休眠【暂停】指定的时间【毫秒】

        void    interrupt() 中断线程休眠【暂停】。会进入异常【InterruptedException】。

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

2.线程的生命周期

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

线程的生命周期描述
    1.新建状态:通过new的方式创建出线程对象,此时线程就进入到创建状态【新建状态】。
               新建状态的线程是不能运行。
              新建状态的线程调用start方法,进入就绪状态

    2.就绪状态:线程具备运行能力,只差操作系统【CPU】分配给他运行时间片【万事具备,只欠时间片】
           得到操作系统【CPU】分配给他运行时间片,此时开始执行run方法,进入运行状态。

    3.运行状态:线程运行run方法。
        回到就绪状态:
        1.操作系统【CPU】分配给他运行时间片使用完毕,回到就绪状态。
        进入阻塞状态
        1.运行状态的线程执行了sleep方法,进入阻塞状态。
        2.运行状态的线程执行了wait方法,进入阻塞状态。
        3.运行状态的线程执行了join方法,进入阻塞状态。
        4.运行状态的线程执行输入/输出动作,进入阻塞状态。
        ......
        进入死亡状态
        1.运行状态的线程run方法执行完毕,进入死亡状态。
        2.运行状态的线程调用stop()/destroy() ,进入死亡状态。
    
    4.阻塞状态:线程暂停运行
        回到运行状态
        阻塞状态中的线程,结束了造成阻塞的原因,此时线程进入就绪状态,得到操作系统【CPU】分配给他运行时间片就可以进入运行状态。
        运行状态进入阻塞状态原因:
        1.运行状态的线程执行了sleep方法,进入阻塞状态,休眠时间结束/interrupt,进入就绪状态
        2.运行状态的线程执行了wait方法,进入阻塞状态,调用notify/notifyAll,进入就绪状态        
        3.运行状态的线程执行了join方法,进入阻塞状态,时间技术/其他线程运行结束,进入就绪状态
        4.运行状态的线程执行输入/输出动作,进入阻塞状态,输入/输出结束,进入就绪状态
        
    5.死亡状态:线程运行结束,释放运行资源。
        死亡状态的线程是不能运行,除非再一次使用strat方法重新启动运行。

3.线程安全

        卖票实例:

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.threaddemo2;

public class MyRunnable implements Runnable{
    private  int  piao=5;
    @Override
    public void run() {
        //得到当前线程的名称
        String  name=Thread.currentThread().getName();
        boolean  flag=true;
        while(flag){
	    //通过代码块
            synchronized(this){
                //判断有没有可卖的票
                if (piao > 0) { //有票可买
                    //收钱--找钱---打印票
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(name + "卖出1张票,还剩" + (--piao) + "张");
                } else {
                    flag = false;
                }
            }
        }
    }
}

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

//同步方法的定义格式: 访问限制修饰符  synchronized  方法返回值类型 方法名称(){ }
    private synchronized boolean  sellpiao(String name){
        //判断有没有可卖的票
        if (piao > 0) { //有票可买
            //收钱--找钱---打印票
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + "卖出1张票,还剩" + (--piao) + "张");
            return  true;
        } else {
            return  false;
        }
    }

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

例如:

package com.wangxing.threaddemo2;

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

public class MyRunnable3 implements Runnable{
    private  int  piao=5;
    private Lock  mylock=new ReentrantLock();
    @Override
    public void run() {
        //得到当前线程的名称
        String  name=Thread.currentThread().getName();
        boolean  flag=true;
        while(flag){
                //设置锁
                mylock.lock();
                //判断有没有可卖的票
                if (piao > 0) { //有票可买
                    //收钱--找钱---打印票
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(name + "卖出1张票,还剩" + (--piao) + "张");
                } else {
                    flag = false;
                }
            //释放锁
            mylock.unlock();
            }
        }
}

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

    Lock:
        1.Lock接口
        2.手动锁定资源,灵活
        3.异常时不会自动释放锁,所以需要在finally中实现释放锁
        4.可以中断锁

死锁
    线程同步在实现的时候会将线程访问的资源锁住,其他的线程不能访问。
    锁死是因为被访问的资源被全部锁住,无法释放,导致线程无法继续执行。
    锁死的具体表现为线程的相互等待。
        A线程等待B线程释放资源继续执行;B线程等待A线程释放资源继续执行.
    减少不必要的线程同步,释放资源,可以接触死锁。

    
线程同步/线程安全
原因:
    当多条线程,同时访问同一个资源的时候,会产生数据不一致的错误情况。

是什么:
    线程同步也叫线程安全,当多条线程,同时访问同一个资源的时候,每一次只能由多条线程中的其中一条访问公共资源,当这一条线程访问公共资源的时候,其他的线程都处于等待状态,不能访问公共资源,当这一条线程访问完了公共资源以后,其他线程中的一条线程才能访问资源,剩下的线程继续等待,等待当前线程访问结束,实现这个过程就是线程同步。【排队访问资源】

怎么做:
    1.synchronized关键字 【同步代码块/同步方法】
    2.通过Lock接口
后果: 死锁 
后果处理: 减少不必要的线程同步,释放资源

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值