Java---多线程的方法

1.线程中常用的方法

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

2.void   start---启动线程

3.String  getName()---返回该线程的名称

   1.当线程没有设置名称时,系统会赋予一个默认的线程名称“Thread-0,Thread-1......”

   2.主线程【主方法的执行线程】的默认名称是"main"

4.void  setName()---设置线程名称

例如:

package com.object.test1;

public class MethodClass implements Runnable{

	@Override
	public void run() {
	for(int i=1;i<=50;i++){
		//1.static Thread currentThread()得到当前正在运行的线程对象
		Thread th=Thread.currentThread();
		//3.String getName()返回该线程的名称。
		String name=th.getName();
		System.out.println(name+"--i--"+i);
	}
 }
}
package com.object.test1;

public class MyMain {

	public static void main(String[] args) {
		//2.主线程【主方法的执行线程】的名称默认是“main”
		String name=Thread.currentThread().getName();
		System.out.println(name);
		//创建目标对象
		MethodClass my1=new MethodClass();
		MethodClass my2=new MethodClass();
		//创建线程对象
		Thread th1=new Thread(my1);
		Thread th2=new Thread(my2);
		//1.当没有设置线程名称的时候,系统会赋予线程一个默认的名称“Thread-0,Thread-1......”
		/*//4.void	setName(String name)设置线程名称
		th1.setName("线程");
		th2.setName("窗口");
		*/
		//2.void start() 启动线程
		th1.start();
		th2.start();
	}

}

  线程的优先级----就是指线程的执行先后,默认情况下所有线程的优先级都是一样的,都是5。

  我们可以通过:

1.void   etPriority(int newPriority)---更改线程优先级

    1.线程的优先级有10个级别,分别是1~10来表示。数字越大优先级越高

    2.为了方便操作,java将10个级别规定成三个级别,分别是最低优先级、中等优先级、

      最高优先级,并且将这3个级别封装成静态常量

         static int MAX_PRIORITY---最高的优先级【10】

         static int  MIN_PRIORITY---最低优先级【1】

         static  int  NORM-PRIORITY---中等优先级【5】

2.int     getPriority()---返回线程的优先级

3.设置现成的优先级时,数字越大优先级越高,数字越小优先级越低。优先级高并不会代表一定就会有限执行,知识被优先执行的几率增大,因此不要试图通过控制线程的优先级来保证某一个线程,总是第一个执行

例如:

package com.object.test2;

public class MethodClass implements Runnable{

	@Override
	public void run() {
	for(int i=1;i<=50;i++){
		//1.static Thread currentThread()得到当前正在运行的线程对象
		Thread th=Thread.currentThread();
		//3.String getName()返回该线程的名称。
		String name=th.getName();
		System.out.println(name+"--i--"+i);
	}
 }
}
package com.object.test2;

public class MyMain {

	public static void main(String[] args) {
		//2.主线程【主方法的执行线程】的名称默认是“main”
		String name=Thread.currentThread().getName();
		System.out.println(name);
		int mainpri=Thread.currentThread().getPriority();
		System.out.println("主方法执行线程的名称=="+name+",优先级=="+mainpri);
		//创建目标对象
		MethodClass my1=new MethodClass();
		//创建线程对象
		Thread th1=new Thread(my1);
		Thread th2=new Thread(my1);
		//4.void	setName(String name)设置线程名称
		th1.setName("线程");
		th2.setName("窗口");
		//void	setPriority(int newPriority) 更改线程的优先级。
		//1.线程的优先级有10个级别,分别使用整数1~10来表示。数字越大优先级越高。
		th1.setPriority(5);
		/*
		 2.为了方便操作,java将10个级别有规定成3个级别,分别是最低的优先级,中等优先级,最高的优先级,并且将这3个级别封装成了静态常量	static int	MAX_PRIORITY 线程可以具有的最高优先级。10
	       static int	MIN_PRIORITY线程可以具有的最低优先级。1
        	static int	NORM_PRIORITY分配给线程的默认优先级。5
		 */
		th2.setPriority(Thread.MAX_PRIORITY);
		//int	getPriority() 返回线程的优先级。
		int in1=th1.getPriority();
		int in2=th2.getPriority();
		System.out.println("线程1优先级"+in1);
		System.out.println("线程2优先级"+in2);
		th1.start();
		th2.start();
	}

}

2.守护线程的相关操作

   用户线程---通常情况下我们所创建的是普通县城,非守护线程,也是守护线程

   守护线程---也叫精灵线程,当所有用户线程执行完毕后,自动结束运行的线程就是守护线程

1.boolean   isDaemom()---测试线程是否为守护线程

2.void   setDaemom()---将该线程标记为守护线程

特征:当所有用户线程都执行完毕以后,无论守护线程能否可以继续运行,都要立刻停止运行。

package com.object.test3;

public class MethodClass implements Runnable{

	@Override
	public void run() {
	for(int i=1;i<=50;i++){
		//1.static Thread currentThread()得到当前正在运行的线程对象
		Thread th=Thread.currentThread();
		//3.String getName()返回该线程的名称。
		String name=th.getName();
		System.out.println(name+"--i--"+i);
	}
 }
}
package com.object.test3;

public class MyThread implements Runnable{

	@Override
	public void run() {
		while(true){
			Thread th=Thread.currentThread();
			String name=th.getName();
			System.out.println(name);
		}
		
	}
	
}
package com.object.test3;

public class MyMain {

	public static void main(String[] args) {
		//创建目标对象
		MethodClass my1=new MethodClass();
		 MyThread my2=new  MyThread();
		 //创建线程对象,并且命名
		 Thread th1=new Thread(my1,"用户线程1");
		 Thread th2=new Thread(my1,"用户线程11");
		 Thread th3=new Thread(my2,"守护线程");
		//void	setDaemon(boolean on) 将该线程标记为守护线程用户线程。
		 th3.setDaemon(true);
		//boolean	 isDaemon() 测试该线程是否为守护线程。
		 System.out.println("用户1--"+th1.isDaemon());
		 System.out.println("用户11--"+th2.isDaemon());
		 System.out.println("守护1--"+th3.isDaemon());
		 //启动线程
		 th1.start();
		 th2.start();
		 th3.start();
	}

}

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

 例如:

package com.object.test4;

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

public class MyAlarm {
	public static void main(String[] args) throws Exception{
		System.out.println("设置一个闹钟:");
		BufferedReader input=new BufferedReader(new InputStreamReader(System.in));
		String nz=input.readLine();
		SimpleDateFormat smd=new SimpleDateFormat("HH:mm:ss");
		boolean flag=true;
		while(flag){
			String dq=smd.format(new Date());
			if(dq.equals(nz)){
				flag=false;
			}
			System.out.println(dq);
			Thread.sleep(1000);
		}
		System.out.println("闹钟响起");
	}

}

 2.void   interrupt()---中断线程休眠【粘贴】会进入异常

例如:

package com.object.test3;

public class MyMain {

	public static void main(String[] args) {
		System.out.println("上课铃声响了");
		//创建目标对象
		MyThreadClass my1=new MyThreadClass();
		//创建线程对象
		Thread th=new Thread(my1);
		//修改名称
		th.setName("张三");
		//启动线程
		th.start();
		System.out.println("老师开始上课");
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("老师发现同学睡着啦");
		System.out.println("老师走过去,踹了一脚!");
		//void	interrupt() 中断线程休眠【暂停】。会进入异常【InterruptedException】。
		th.interrupt();
	}

}

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

例如:

package com.object.test3;

public class MyMain {

	public static void main(String[] args) {
		//创建目标对象
		MethodClass my1=new MethodClass();
		 MyThread my2=new  MyThread();
		 //创建线程对象,并且命名
		 Thread th1=new Thread(my1,"用户线程1");
		 Thread th2=new Thread(my1,"用户线程11");
		 Thread th3=new Thread(my2,"守护线程");
		//void	setDaemon(boolean on) 将该线程标记为守护线程用户线程。
		 th3.setDaemon(true);
		//boolean	 isDaemon() 测试该线程是否为守护线程。
		 System.out.println("用户1--"+th1.isDaemon());
		 System.out.println("用户11--"+th2.isDaemon());
		 System.out.println("守护1--"+th3.isDaemon());
		 //启动线程
		 th1.start();
		 th2.start();
		 th3.start();
	}

}

3.线程的生命周期

 1.线程生命周期就是线程从一开始新建,到run方法执行完毕以后的状态变化.[状态之间的切换]

 2.线城生命周期的几种状态【1.新建状态;2.就绪状态;3.运行状态;4.阻塞状态;5.死亡状态】

3.线程的生命周期描述 

  1.新建状态

    通过new的方式创建出线程对象,此时线程就进入到创建状态【新建状态】

    新建状态的线程是不能运行的

    新建状态的线程调用start方法,进入就绪状态

 2.就绪状态

    线程具备运行能力,只差操作系统[CPU]费赔给运行时间片

    得到操作系统[CPU]给的运行片时,开始执行run方法,进入运行状态

 3.运行状态:线程运行run方法

    回到就绪状态:

     1.操作系统[CPU]分配给运行时间使用完毕后,就会回到就绪状态

     进入阻塞状态:

       1.运行状态执行sleep方法,进入阻塞状态

       2.运行状态执行了wait方法,进入阻塞状态。

       3.运行状态执行了输入/输出动作。进入阻塞状态

  4.阻塞状态:线程运行暂停

     回到运行状态

       阻塞状态中的县城,结束了造成阻塞的原因,此时线程进入就绪状态,得到操作系统[CPU]配         给他的运行状态就可以进入运行状态

     运行状态进入阻塞状态原因:

      1.运行状态执行sleep方法,进入阻塞状态,结束休眠时间/interrupt,进入运行状态

      2.运行状态执行wait方法,进入阻塞状态,调用notify/notifyAll,进入就绪状态

      3.运行状态执行输入输出动作,进入阻塞状态,输入/输出结束后就可以进入就绪状态

5.死亡状态:线程运行结束,释放运行资源

   死亡状态的线程是不能运行的,除非再一次使用start方法重新启动运行。

4.线程安全

 1.   买票实例:

package com.object.test6;

public class MyThreadClass implements Runnable{
	private int ticket=5;
	public void run() {
		//得到线程名称
		String name=Thread.currentThread().getName();
		//持续买票
		boolean flag=true;
		//只要有票就一直卖
		while(flag){
			//判断有没有票卖
			if(ticket>0){
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(name+",卖出1张票,还剩"+(--ticket)+"张");
			}else{
				flag=false;
			}
		}
	}
}
package com.object.test6;

public class MyMain {

	public static void main(String[] args) {
		//创建目标对象
		MyThreadClass my=new MyThreadClass();
		//创建线程对象
		Thread th=new Thread(my);
		Thread th2=new Thread(my);
		Thread th3=new Thread(my);
		//修改线程名称
		th.setName("窗口1");
		th2.setName("窗口2");
		th3.setName("窗口3");
		//启动线程
		th.start();
		th2.start();
		th3.start();
	}

}

 2.分析结果: 

   当窗口3卖出最后一张票时,在收钱打印的时候,还没来得及进行减1线程就切换到了窗口2,这是窗口2就认为还有一张票,然后就在窗口2进行了收钱打印时,还没来得及对票数减1县城就切换到窗口3,这时窗口3就会对票数进行减1,完成以后切换给窗口2,窗口2再进行减1,此时就导致了出现-1的这个值

   经过上面运行程序的分析,我得到的结果是:

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

   为了解决这种数据不一致的错误情况,我们才学习线程同步。

 3.什么是线程同步/线程安全

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

  线程同步[线程安全]的实现方式:

    1. Synchronized关键字【同步代码块/同步方法】

 1.同步代码块

       格式:synchronized(同步对象){ }

缺点:使用时需要设置同步对象,由于很多时候不知道同步对象是谁,容易写错,导致思索的情况,正是因为这也原因很少使用同步代码块来实现线程同步。

例如:

package com.object.test6;

public class MyThreadClass2 implements Runnable {
	private int ticket = 5;
	public void run() {
		// 得到线程名称
		String name = Thread.currentThread().getName();
		// 持续买票
		boolean flag = true;
		// 只要有票就一直卖
		while (flag) {
			synchronized (this) {
				// 判断有没有票卖
				if (ticket > 0) {
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(name + ",卖出1张票,还剩" + (--ticket) + "张");
				} else {
					flag = false;
				}
			}
		}
	}
}
package com.object.test6;

public class MyMain {

	public static void main(String[] args) {
		//创建目标对象
		MyThreadClass2 my=new MyThreadClass2();
		//创建线程对象
		Thread th=new Thread(my);
		Thread th2=new Thread(my);
		Thread th3=new Thread(my);
		//修改线程名称
		th.setName("窗口1");
		th2.setName("窗口2");
		th3.setName("窗口3");
		//启动线程
		th.start();
		th2.start();
		th3.start();
	}

}

2.同步方法

  同步方法的定义格式:

    访问限制修饰符  synchronized 访问返回值类型  方法mingcheng(){ }

例如:

package com.object.test6;

public class MyThreadClass3 implements Runnable {
	private int ticket = 5;
	// 持续买票
	boolean flag = true;
	public void run() {
		// 得到线程名称
		String name = Thread.currentThread().getName();
		// 只要有票就一直卖
		while (flag) {
			 sell(name);
		}
	}
	//同步方法
	public synchronized void sell(String name){
		// 判断有没有票卖
		if (ticket > 0) {
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(name + ",卖出1张票,还剩" + (--ticket) + "张");
		} else {
			flag = false;
		}
	}
}
package com.object.test6;

public class MyMain {

	public static void main(String[] args) {
		//创建目标对象
		MyThreadClass3 my=new MyThreadClass3();
		//创建线程对象
		Thread th=new Thread(my);
		Thread th2=new Thread(my);
		Thread th3=new Thread(my);
		//修改线程名称
		th.setName("窗口1");
		th2.setName("窗口2");
		th3.setName("窗口3");
		//启动线程
		th.start();
		th2.start();
		th3.start();
	}

}

3.通过Lock接口

  1. 格式:

      public interface Lock

 2.常用的接口方法

        void    lock() 获得锁。 

        void    unlock() 释放锁。

由于上面的锁方法是Lock接口,我们要使用就得先创建出Lock接口对象,由于Lock是个接口不能new ,我们就得使用它的子类来创建对象。Lock接口得子类ReentrantLock

例如:

package com.object.test6;

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

public class MyThreadClass4 implements Runnable {
	private int ticket = 5;
	private Lock mylock=new ReentrantLock();
	public void run() {
		// 得到线程名称
		String name = Thread.currentThread().getName();
		// 持续买票
		boolean flag = true;
		// 只要有票就一直卖
		while (flag) {
			//void	lock() 获得锁。 
			mylock.lock();
				// 判断有没有票卖
				if (ticket > 0) {
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(name + ",卖出1张票,还剩" + (--ticket) + "张");
				} else {
					flag = false;
				}
				//void	unlock() 释放锁。
				mylock.unlock();
		}
	}
}
package com.object.test6;

public class MyMain {

	public static void main(String[] args) {
		//创建目标对象
		MyThreadClass4 my=new MyThreadClass4();
		//创建线程对象
		Thread th=new Thread(my);
		Thread th2=new Thread(my);
		Thread th3=new Thread(my);
		//修改线程名称
		th.setName("窗口1");
		th2.setName("窗口2");
		th3.setName("窗口3");
		//启动线程
		th.start();
		th2.start();
		th3.start();
	}

}

5.Synchronized关键字与Lock接口的区别?

synchronizedLock
synchronized关键字Lock接口
自动锁定资源,不灵活手动锁定资源,灵活
异常时会自动释放锁异常时不会自动释放锁,所以需要在finally中实现释放锁
不能中断锁,必须等待线程执行完成释放锁可以中断锁
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值