赞
踩
就是进程中的一个独立控制单元,线程在控制着进程的执行。一个进程中至少有一个进程。
多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。
多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。
注意:
线程是一个动态执行的过程,它也有一个从产生到死亡的过程。
下图显示了一个线程完整的生命周期。
由图可知一共有五种状态:
新建状态
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
就绪状态
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
运行状态
如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
阻塞状态
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
死亡状态
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
步骤:
代码如下:
package com.kuang.demo01; public class TestThread1 extends Thread{ @Override public void run() { for (int i = 0; i < 2000; i++) { System.out.println("--i"); } } public static void main(String[] args) { TestThread1 testThread1= new TestThread1(); testThread1.start(); for (int i = 0; i < 2000; i++) { System.out.println("i--"); } } }
接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run 的无参方法。
步骤:
代码如下:
package com.kuang.demo01; //创建线程方式2:实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法 public class TestThread3 implements Runnable{ @Override public void run() { //run方法线程体 for (int i = 0; i < 200; i++) { System.out.println("我在看代码----" + i); } } public static void main(String[] args) { //创建runnable接口的实现类对象 TestThread3 testThread3 = new TestThread3(); //创建线程对象,通过线程对象来开启我们的线程,代理 // Thread thread = new Thread(testThread3); // // thread.start(); new Thread(testThread3).start(); for (int i = 0; i < 1000; i++) { System.out.println("我在学习多线程---" + i); } } }
步骤:
代码如下:
package com.gaoji; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; //实现callable接口 class Callable implements java.util.concurrent.Callable<Integer> { @Override public Integer call() throws Exception { return 100; } } public class ThreadNer{ public static void main(String[] args) { FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable()); new Thread(futureTask).start(); try { Integer integer = futureTask.get(); System.out.println(integer); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
线程睡眠的原因:线程执行的太快,或需要强制执行到下一个线程。
线程睡眠的方法(两个):
sleep(long millis)在指定的毫秒数内让正在执行的线程休眠
sleep(long millis,int nanos)在指定的毫秒数加指定的纳秒数内让正在执行的线程休眠
代码如下:
package com.state; import java.text.SimpleDateFormat; import java.util.Date; import java.util.logging.SimpleFormatter; public class TestSleep2 { public static void main(String[] args) { Date startTime = new Date(System.currentTimeMillis());//获取系统当前时间 while(true){ try { Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime)); startTime = new Date(System.currentTimeMillis());//更新当前时间 } catch (InterruptedException e) { e.printStackTrace(); } } } //模拟倒计时 public void tenDown() throws InterruptedException{ int num = 10; while(true){ Thread.sleep(1000); System.out.println(num--); if(num <= 0){ break; } } } }
该方法和sleep方法类似,也是Thread类提供的一个静态方法,可以让正在执行的线程暂停,但是不会进入阻塞状态,而是直接进入就绪状态。相当于只是将当前线程暂停一下,然后重新进入就绪的线程池中,让线程调度器重新调度一次。也会出现某个线程调用yield方法后暂停,但之后调度器又将其调度出来重新进入到运行状态。
代码如下:
package com.state; class MyYield implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"线程开始执行"); Thread.yield(); System.out.println(Thread.currentThread().getName()+"线程结束执行"); } } public class TestYield{ public static void main(String[] args) { MyYield myYield = new MyYield(); new Thread(myYield,"a").start(); new Thread(myYield,"b").start(); } }
sleep和yield的区别:
当B线程执行到了A线程的.join()方法时,B线程就会等待,等A线程都执行完毕,B线程才会执行。
join可以用来临时加入线程执行。
代码如下:
package com.state; //测试join方法 //想象为插队 public class TestJoin implements Runnable{ @Override public void run() { for (int i = 0; i < 1000; i++) { System.out.println("线程VIP来了" + i); } } public static void main(String[] args) { //启动我们的线程 TestJoin testJoin = new TestJoin(); Thread thread = new Thread(testJoin); thread.start(); //主线程 for (int i = 0; i < 500; i++) { if(i == 200){ try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("main" + i); } } }
原stop方法因有缺陷已经停用了,那么现在改如何停止线程?现在分享一种,就是让run方法结束。
开启多线程运行,运行的代码通常是循环结构,只要控制住循环,就可以让run方法结束,也就是线程结束。
代码如下:
package com.state; import com.kuang.demo02.TestCallable; //测试stop //1.建议线程正常停止-->利用次数,不建议死循环 //2.建议使用标志位-->设置一个标志位 //3.不要使用stop或者destroy等过时或者JDK不建议使用的方法 public class TestStop implements Runnable{ //1.设置一个标识位 private boolean flag = true; @Override public void run() { int i = 0; while(flag){ System.out.println("run....Thread" + i++); } } //2.设置一个公开的方法停止线程,转换标志位 public void stop(){ this.flag = false; } public static void main(String[] args) { TestStop testStop = new TestStop(); new Thread(testStop).start(); for (int i = 0; i < 1000; i++) { System.out.println("main" + i); //调用stop方法切换标志位,让线程停止 if(i == 900){ testStop.stop(); System.out.println("线程停止了"); } } } }
特殊情况:当线程处于了冻结状态,就不会读取到标记,也就不会结束。当没有指定方法让冻结的线程回复到运行状态时,我们需要对冻结状态进行清除,也就是强制让线程恢复到运行状态中来,这样可就可以操作标记让线程结束。
Thread类提供该方法: interrupt();(如果线程在调用Object类的wait()、wait(long)、wait(long,int)方法,或者该类的join()、join(long)、join(long、int)、sleep(long)或sleep(long、int)方法过程中受阻,则其中断状态将被清除,还将收到一个InterruptedException。)
每个线程执行时都有一个优先级的属性,优先级高的线程可以获得较多的执行机会,而优先级低的线程则获得较少的执行机会。与线程休眠类似,线程的优先级仍然无法保障线程的执行次序。只不过,优先级高的线程获取CPU资源的概率较大,优先级低的也并非没机会执行。
** 代码如下:**
package com.state; public class TestPriority { public static void main(String[] args) { System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority()); MyPriority myPriority = new MyPriority(); Thread t1 = new Thread(myPriority); Thread t2 = new Thread(myPriority); Thread t3 = new Thread(myPriority); Thread t4 = new Thread(myPriority); Thread t5 = new Thread(myPriority); Thread t6 = new Thread(myPriority); t1.start(); t2.setPriority(1); t2.start(); t3.setPriority(4); t3.start(); t4.setPriority(Thread.MAX_PRIORITY); t4.start(); } } class MyPriority implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority()); } }
java允许多线程并发控制,当多个线程同时操作一个可共享资源变量时(如对其进行增删改查操作),会导致数据不准确,而且相互之间产生冲突。所以加入同步锁以避免该线程在没有完成操作前被其他线程调用,从而保证该变量的唯一性和准确性。
在介绍同步方法之前先演示一下当多个线程操作一个共享资源时可能会发生的错误,这里用的方法是让线程在执行时睡眠10毫秒,会导致多个线程去操作同一个资源变量。
** 代码如下:**
package com.gaoji; import java.util.concurrent.locks.ReentrantLock; public class TestLock { public static void main(String[] args) { TestLock2 t1 =new TestLock2(); new Thread(t1).start(); new Thread(t1).start(); new Thread(t1).start(); } } class TestLock2 implements Runnable{ int ticketNums = 10; //定义lock锁 private final ReentrantLock lock = new ReentrantLock(); @Override public void run() { while(true){ try { lock.lock(); if(ticketNums > 0) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(ticketNums--); }else { break; } }finally { //解锁 lock.unlock(); } } } }
同步方法1:
同步函数:就是用synchronize关键字修饰的方法。因为每个java对象都有一个内置锁,当用synchronize关键字修饰方法时内置锁会保护整个方法,而在调用该方法之前,要先获得内置锁,否则就会处于阻塞状态。
public synchronized void run() {
}
同步方法2:
同步代码块:就是拥有synchronize关键字修饰的语句块,被该关键字修饰的语句块会自动被加上内置锁,从而实现同步。
public void run() {
while(true){
synchronized (this) { //同步代码块
if(tick>0){
try {
Thread.sleep(10); //执行中让线程睡眠10毫秒,
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " " + tick--);
}
}
}
}
进程A中包含资源A,进程B中包含资源B,A的下一步需要资源B,B的下一步需要资源A,所以它们就互相等待对方占有的资源释放,所以也就产生了一个循环等待死锁。
代码如下:
package com.gaoji; import java.util.concurrent.locks.ReentrantLock; public class TestLock { public static void main(String[] args) { TestLock2 t1 =new TestLock2(); new Thread(t1).start(); new Thread(t1).start(); new Thread(t1).start(); } } class TestLock2 implements Runnable{ int ticketNums = 10; //定义lock锁 private final ReentrantLock lock = new ReentrantLock(); @Override public void run() { while(true){ try { lock.lock(); if(ticketNums > 0) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(ticketNums--); }else { break; } }finally { //解锁 lock.unlock(); } } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。