-
程序、进程、线程
程序:可执行的代码段
进程:正在运行的程序
线程:进程可以细分为线程,是程序的内部的一条执行路径 -
单核CPU和多核CPU
单核cpu的多线程是一种假的多线程。它实际上是多个程序不断地切换。
多核cpu才可以实现真正的多线程
2.1 并行和并发
并行:多个cpu同时执行多个任务。
并发:一个cpu同时执行多个任务
2.2 多线程优点
多线程的效率并不会比单线程高,但是多线程处理任务的总时间会低于单线程。
1,提高响应
2,提高cpu利用率
3,改善程序结构。使利于运行和修改
2.3 应用场景
当需要同时执行多个任务时。
程序需要实现等待。
需要一些后台运行时 -
线程的创建
3.1通过继承实现
public static void main(String[] args) {
// 创建类,继承thread类。覆写run方法,
Thread r = new Test();
// 启动线程,调用当前对象的start方法
r.start();
for (int i = 0; i < 10; i++) {
System.out.println(“m1-” + i);
}
}
}
class Test extends Thread {
// run相当于新县城中的main方法,是程序执行的起点和终点。
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(“n1-” + i);
}
}
3.2通过implements Runnable
public static void main(String[] args) {
Thread t=new Thread(new Test1());
t.start();
for (int i = 0; i < 10; i++) {
System.out.println(“m” + i);
}
}
// public static void test() {
// Thread t = new Thread(new Test1());
// t.start();
// for (int i = 0; i < 10; i++) {
// System.out.println(“m” + i);
// }
// }
}
//实现runnable接口,覆写run方法。启动线程,调用thread的start方法。
class Test1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(“n” + i);
}
} -
常用方法
Thread t=new Thread();
t.start();
t.setName();默认时Thread-0/1依次类推
getName();
setPriority();设置优先级
getPriority();获取优先级
Static currentThread();获取当前线程的地址
Static sleep();让当前线程睡眠~~
4.1 SetPrioritypackage _01_Test; public class _03_SetPriority { public static void main(String[] args) { Thread t1 = new Test3(); Thread t2 = new Test3(); // 设置名字,最好在启动之前设置,默认Thread-0,以此类推 Thread.currentThread().setName("C"); Thread.currentThread().setPriority(10); t1.setName("A"); t2.setName("B"); t2.setPriority(5); t1.setPriority(1); t1.start(); t2.start(); for (int i = 0; i < 10; i++) { // currentThread 获取当前线程对象,静态方法,写在哪个线程就获取哪个线程对象 System.out.println("name-"+Thread.currentThread().getName() ); try { // sleep 让当前线程睡眠,静态方法,和谁调用无关,写在哪个线程,就睡眠哪个线程 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Test3 extends Thread { public void run() { for (int i = 0; i < 9; i++) { System.out.println("name-" + this.getName()); try { // sleep 让当前线程睡眠,静态方法,写在哪个线程,就睡眠哪个线程 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }
4.2 Interrupt
package _01_Test; /** * 20 sleep() 让当前线程进入睡眠,静态方法,传入睡眠毫秒数 * * interrupt() : 强制唤醒正在睡眠的这个线程,会抛异常 */ public class _04_Interrupt { public static void main(String[] args) { Thread t = new Thread(new Test4()); t.start(); try { Thread.sleep(500); t.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } } } class Test4 implements Runnable { @Override public void run() { try { Thread.sleep(15000); System.out.println("Zhu"); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("Bei"); } System.out.println("Work"); } }
4.3Join
package _01_Test; public class _05_Join { public static void main(String[] args) throws InterruptedException { Thread t=new Test5(); Thread t1=new Test5(); t.setName("t"); t1.setName("t1"); t.start(); t1.start(); t.join(); for(int i=0;i<10;i++){ System.out.println("0"+Thread.currentThread().getName()); } } } class Test5 extends Thread{ public void run(){ for(int i=0;i<10;i++){ System.out.println("5"+Thread.currentThread().getName()); } } }
4.4Thread.yield()
package _01_Test; /** * 20 Thread.yield() : 静态方法,让出当前执行的时间片,让其他线程执行 * * 1 静态方法,写在哪里,哪里让位 2 相同优先级让位,不同优先级不让位 * * 优先级默认是 5 , 子类继承父类优先级 */ public class _06_Yield { public static void main(String[] args) { Thread t = new Thread(new Test6()); t.setName("t"); t.start(); for (int i = 0; i < 10; i++) { // 让位 Thread.yield(); System.out.println(Thread.currentThread().getName() + "B" + i); } } } class Test6 implements Runnable { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + "A" + i); } } }
4.5Stop
package _01_Test; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** * 20 stop : 终止一个线程,容易导致死锁,所以已经过时,不推荐使用 * * 推荐使用标识符的方式来结束 * */ public class _07_Stop { public static void main(String[] args) throws ParseException { Test7 m = new Test7(); Thread t = new Thread(m); t.start(); try { Thread.sleep(3000); //不在使用flag // t.stop(); m.flag = false; } catch (InterruptedException e) { e.printStackTrace(); } } } class Test7 implements Runnable { boolean flag = true; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); @Override public void run() { // 标志符,false就终止 while (flag) { System.out.println(sdf.format(new Date())); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }
4.6Synchronization
package _01_Test; /** * 20 线程同步 : 当多个线程有可能操作同一个数据的时候,为了保证数据的一致性,需要对当前操作进行同步处理 线程同步本质是数据的同步,是一种安全机制 * 尤其是对数据进行更改操作,必须要使用同步机制,如果只是查询,就无所谓了 * * 异步编程 线程之间完全是独立的,同时进行,但相互不影响 同步编程 线程之间不是独立的,同时进行,但是相互有影响, * 所以这时需要某个线程单独执行完某个操作之后,再让其他线程执行 * * 同步条件 1 必须多线程 2 多个线程必须有可能同时操作某一个共享数据 3 主要是涉及数据的更改操作 * * 方法锁 : synchronized 修饰符,修饰的方法,不能同时被多个线程执行 如果访问某一个对象中 加锁的 成员方法,则该对象中所有加锁的成员方法, * 都不能被其他线程访问 如果访问一个类中 加锁的静态方法,则该类中所有加锁的静态方法 都不能被其他线程访问 * */ public class _08_Synchronization { public static void main(String[] args) { Account a = new Account(1000); Thread t1 = new Thread(new Test8(a)); Thread t2 = new Thread(new Test8(a)); t1.setName("HH"); t2.setName("OO"); t1.start(); t2.start(); } } class Test8 implements Runnable { Account account; // 使account他们相关联,指向withDraw public Test8(Account account) { this.account = account; } @Override public void run() { account.withDraw(100); } } class Account { private double re; public double getRe() { return re; } public void setRe(double re) { this.re = re; } public Account(double re) { super(); this.re = re; } public void withDraw(double money) { System.out.println(Thread.currentThread().getName()); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (this) { re -= money; System.out.println(Thread.currentThread().getName() + "取钱后" + "剩余:" + getRe()); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } } }
4.7lock
package _01_Test; /** * 20 */ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class _09_Lock { public static void main(String[] args) { Account1 a=new Account1(1000); Thread t1=new Thread(new Test9(a)); Thread t2=new Thread(new Test9(a)); t1.setName("OO"); t2.setName("NN"); t1.start(); t2.start(); } } class Test9 implements Runnable{ Account1 account; public Test9(Account1 account){ this.account=account; } @Override public void run() { account.withDraw(100); } } class Account1{ private double re; public double getRe() { return re; } public void setRe(double re) { this.re = re; } public Account1(double re) { super(); this.re = re; } Lock lock=new ReentrantLock(); public void withDraw(double money){ System.out.println(Thread.currentThread() .getName()); try{ Thread.sleep(300); }catch(InterruptedException e){ e.printStackTrace(); } lock.lock(); try{ re-=money; System.out.println(Thread.currentThread().getName()+"取后剩余"+getRe()); }finally{ lock.unlock(); } } }
4.8Daemon
package _01_Test; /**20 * 守护线程 : 又称为兜底线程 * 每个程序运行当中,都会默认开启一个守护线程用于监听我们的正常程序 * 当没有任何一个线程执行的时候,JVM就需要退出了,这个时候守护线程也会退出 * Thread类中 提供了 setDaemon() 方法 可以设置某个线程为守护线程 */ public class _10_Daemon { public static void main(String[] args) { //添加线程t,设置名字t1 Thread t=new Thread(new Test10()); t.setName("t1"); //为t1设置守护线程 t.setDaemon(true); //开始t1 t.start(); for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName()+" "+i); try{ Thread.sleep(300); }catch(InterruptedException e){ e.printStackTrace(); } } } } class Test10 implements Runnable{ @Override public void run() { for(int i=0;true;i++){ System.out.println(Thread.currentThread().getName()+" "+i); try{ Thread.sleep(300); }catch(InterruptedException e){ e.printStackTrace(); } } } }
4.9Timer
package _01_Test; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class _11_Timer { public static void main(String[] args) throws ParseException { //创建定时器 Timer time=new Timer(); //设置定时开始时间,过了设定时间就开始运行 String str="2021/04/18 12:36:59 123"; SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss SSS"); Date date=sdf.parse(str); //在这里,date参数那里还可以传入时间毫秒数。500是间隔时间 time.schedule(new logTimerTask(),date,500); time.schedule(new logTimerTask(), 2000, 500); } } class logTimerTask extends TimerTask{ @Override public void run() { SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss SSS"); System.out.println(sdf.format(new Date())); } }
-
生命周期
JDK中用Thread.State类定义了线程的几种状态
要想实现多线程,必须在主线程中创建新的线程对象。Java语言使用Thread类 及其子类的对象来表示线程,在它的一个完整的生命周期中通常要经历如下的五 种状态:
新建: 当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建 状态
就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件,只是没分配到CPU资源
运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态, run()方法定义了线 程的操作和功能
阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU 并临时中止自己的执行,进入阻塞状态
死亡:线程完成了它的全部工作或线程被提前强制性地中止或出现异常导致结束 -
线程控制
1.结束线程
2.线程同步锁 synchronized和lock
3.守护线程
4.定时器
多线程&实例
最新推荐文章于 2023-08-29 14:35:26 发布