一、多线程概述package com.laobi.day12;
public class ThreadTest01 {
/**
* 进程:正在进行中的程序(直译)
*
* 线程:就是进程中一个程序执行的控制单元(执行路径)
* 一个进程中可以多执行路径,称之为多线程
*
* 一个进程中至少要有一个线程
*
* 开启多个线程是为了同时运行多部分代码
*
* 每一个线程都有自己运行的内容。这个内容可以称为线程要执行的任务
*
* 多线程的好处:解决了多部分同时运行的问题
* 多线程的弊端:线程太多会导致效率的降低
*
* 其实应用程序的执行都是cpu在做着快速的切换完成的。这个切换时随机的。
*
* jvn启动时就启动了多个线程,至少有两个线程可以分析出来的
* 1、执行main函数的线程
* 该线程的任务代码都定义在main函数中
* 2、负责垃圾回收的线程
*
*
* @param artcool
*/
public static void main(String[] args) {
Demo d1 = new Demo("旺财"); //主线程运行示例
Demo d2 = new Demo("小强");
d1.show();
d2.show();
// new Demo(); jvm线程演示
// System.gc();
System.out.println("diu");
}
}
class Demo
{
private String name;
public Demo(String name) {
super();
this.name = name;
}
public void show()
{
for(int x=0;x<10;x++)
{
for(int y=0;y<999999999;y++){}
System.out.println("demo 走"+name+"..."+x);
}
}
}
二、创建线程
package com.laobi.day12;
public class ThreadTest02 {
/**
* 如何创建一个线程呢?
* 创建线程方式一:继承Thread类
*
* 步骤:
* 1、定义一个类继承Thread类。
*
* 2、覆盖Thread类中的run方法。
*
* 3、直接创建Thread的子类对象
* 4、调用start方法开启线程并调用线程的任务run方法执行
*
* 可以通过Thread的getName获取线程的名称 Thread——编号
*
* 主线程的名字就是main
* @param args
*/
public static void main(String[] args) {
/*创建线程的目的是为了开启一条执行路径,去运行指定的代码和其他代码实现同时运行
而运行的指定代码就是这个执行路径的主任务
jvm创建的主线程的任务都定义在了主函数中
而自定义的线程它的任务在哪?
Thread类用于描述线程,线程是需要任务的。所以Thread类也对任务的描述
这个任务就是通过Thread类中的run方法来体现。也就是说,run方法就是封装自定义线程运行任务的函数
run方法中定义就是线程要运行的代码任务
开启线程是为了运行指定代码,所以只有继承Thread类,并复写run方法
*/
// Thread t1 = new Thread();
Demo2 d1 = new Demo2("jack");
Demo2 d2 = new Demo2("tom");
d1.start();
d2.start();
}
}
class Demo2 extends Thread
{
private String name;
Demo2(String name)
{
this.name = name;
}
public void run()
{
show();
}
public void show()
{
for(int x=0;x<10;x++)
{
for(int y=0;y<999999;y++)
{
}
System.out.println(name+"...."+x+"..."+Thread.currentThread().getName());
}
}
}
三、Thread类的基本获取和设置方法
1)获取线程名字
Thread类中方法 String getName()
在一个不是Thread子类中获取名字:
Thread类中静态方法
static Thread currentThread()
返回正在运行的,当前线程对象 Thread类对象
继续使用线程对象的 getName()获取线程的名字
Thread类的方法 void setName(String name)设置线程名
Thread(String name) 用的是Thread类构造方法
子类使用super访问父类构造器
在Thread子类中,获取线程名字,直接使用父类方法getName()
在不是Thread子类中,通用代码,Thread.currentThread().getName()
四、线程的优先级的获取和设置
Thread类方法getPriority() 获取到优先级
Thread类方法setPriority(int t) 设置优先级
package com.test.xiancheng;
public class Test07 {
/**
*线程的生命周期及状态转换
*1、新建状态(new)
* 创建一个线程对象后,该线程对象就处于新建状态,此时它不能运行,和其他Java对象
* 一样,仅仅由Java虚拟机为其分配了内存,没有表现出任何线程的动态特征
*2、就绪状态(runnable)
* 当线程对象调用了Start()方法后,线程就进入就绪状态了。
* 此时它只是具备了运行条件,能否获得cpu的使用权开始运行,还需要等待系统的调度
*3、运行状态(running)
* 如果出就绪状态的线程获得了cpu的使用权,开始执行run()方法中的线程执行体,则该线程处于运行状态。
*4、阻塞状态(blocked)
* 一个正在执行的线程在某些特殊情况下,如执行耗时的输入/输出操作时,会放弃cpu使用权,进入阻塞状态。
* 阻塞就不能进入阻塞状态后,就不能进入排队队列。
* 例举一下线程由运行状态转换成阻塞状态的原因
* a、当线程试图获取某个对象的同步锁时,如果该锁被其他线程所持有,则当前线程会进入阻塞状态,
* 如果想从阻塞状态进入就绪状态必须获得其他线程所持有的锁
* b、当线程调用了一个阻塞式的io方法时,该线程就会进入阻塞状态,如果想进入就绪状态就必须要等到这个阻塞的
* io方法返回
* c、当线程调用了某个对象的wait()时,也会使线程进入阻塞状态,如果想进入就绪状态就需要使用
* notify()方法唤醒该线程
* d、当线程调用了Thread的sleep(long mills)方法时,也会使线程进入阻塞状态,在这种情况下
* 只需等到线程的睡眠时间到了以后,线程就会自动进入就绪状态
* f、当在一个线程中调用另一个线程的join()方法时,会使当前线程进入阻塞状态,在这种情况下,需要等到
* 需要等到新加入的线程运行结束后才会结束阻塞状态,进入就绪状态
* 线程从阻塞状态只能进入就绪状态
*5、死亡状态(Terminated)
* 线程的run()方法正常执行完毕或者线程抛出一个未捕获的异常(Exception)、错误(Error),线程
* 就会进入死亡状态。一旦进入死亡状态I,线程将不再拥有运行的资格,也不能再转换到其他状态
*
*
*线程的调度:分别是分时调度模型和抢占式调度模型
*分时调度:让所用的线程轮流获得cpu的使用权,并且平均分配cpu的时间片
*抢占式调度:让可运行池中优先级高的线程优先占用cpu,而对优先级相同的
* 线程,随机选择一个线程占用cpu,当它失去cpu的使用权后,
* 再随机选择其他线程获取cpu使用权。
*1、线程的优先级:
* 如果需要对线程进行调度,最直接的方式就是设置线程的优先级
*2、线程休眠:
* 使正在执行的线程暂停,将cpu让给别的线程,这是可以使用sleep(),该方法可以让当前正在执行
* 的线程暂停一段时间,进入休眠等待状态。
*3、线程让步:
* 可以通过yield()方法来实现,该方法和sleep有点相似,都可以让正在运行的线程暂停,
* 区别在于yield()方法不会阻塞线程,他只是将线程转换成就绪状态,让系统调度器重新调度一次
*4、线程插队:
* 当在某个线程中调用其他线程的join()方法时,调用的线程将被阻塞,直到
* 被join()方法加入的线程执行完成后他才会继续运行
*
*
* 多线程同步:
* 1、线程安全
* 2、线程同步方法
* 3、同步方法:当把共享资源的操作放在synchronized定义的区域内时,便为这些操作加了同步锁
* 在方法前面同样可以使用synchronized关键字来修饰,被修饰的方法为同步方法,它能实现
* 和同步代码块同样的功能。被synchronized修饰的方法在某一时刻只允许一个线程访问
* ,访问该方法的其他线程都会被阻塞,直到当前线程访问完毕后,其他线程才有机会执行方法
*
*/
public static void main(String[] args) {
Thread minPriorty = new Thread(new MinProirty(),"优先级较低的线程");
Thread maxPriorty = new Thread(new MaxPriorty(),"优先级较高的线程");
minPriorty.setPriority(Thread.MIN_PRIORITY);
maxPriorty.setPriority(10);
maxPriorty.start();
minPriorty.start();
}
}
class MaxPriorty implements Runnable
{
public void run()
{
for(int i=0;i<=10;i++)
{
System.out.println(Thread.currentThread().getName()+"正在输出:"+i);
}
}
}
class MinProirty implements Runnable
{
public void run()
{
for(int i=0;i<=10;i++)
{
System.out.println(Thread.currentThread().getName()+"正在输出:"+i);
}
}
}
五、线程休眠
package com.test.xiancheng;
public class XCxiumian {
/**
* 线程休眠:
* 使正在执行的线程暂停,将cpu让给别的线程,这是可以使用sleep(),该方法可以让当前正在执行
* 的线程暂停一段时间,进入休眠等待状态。
* @throws Exception
*/
public static void main(String[] args) throws Exception {
new Thread(new SleepThread()).start();
for(int i=1;i<=10;i++)
{
if(i==5)
{
Thread.sleep(2000);
}
System.out.println("主线程正在输出:"+i);
Thread.sleep(500);
}
}
}
class SleepThread implements Runnable
{
public void run()
{
for(int i=1;i<=10;i++)
{
if(i==3)
{
try
{
Thread.sleep(2000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
System.out.println("线程一正在输出:"+i);
try
{
Thread.sleep(500);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
五、线程让步
package com.test.xiancheng;
public class XCrangbu {
/**
* 线程让步:
* 可以通过yield()方法来实现,该方法和sleep有点相似,都可以让正在运行的线程暂停,
* 区别在于yield()方法不会阻塞线程,他只是将线程转换成就绪状态,让系统调度器重新调度一次
*
*/
public static void main(String[] args) {
Thread t1 = new YieldThread("线程A");
Thread t2 = new YieldThread("线程B");
t1.start();
t2.start();
}
}
class YieldThread extends Thread
{
public YieldThread(String name)
{
super(name);
}
public void run()
{
for(int i=0;i<5;i++)
{
System.out.println(Thread.currentThread().getName()+"----"+i);
if(i==3)
{
System.out.print("线程让步:");
Thread.yield();//线程运行到此,做出让步
}
}
}
}
六、线程插队
package com.test.xiancheng;
public class XCchadui {
public static void main(String[] args) throws Exception {
Thread t = new Thread(new EmergencyThread(),"线程一");
t.start();
for(int i=1;i<6;i++)
{
System.out.println(Thread.currentThread().getName()+"输入:"+i);
if(i==2)
{
t.join();
}
Thread.sleep(500);
}
}
}
class EmergencyThread implements Runnable
{
public void run()
{
for(int i=1;i<6;i++)
{
System.out.println(Thread.currentThread().getName()+"输入:"+i);
try
{
Thread.sleep(500);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}