1. 实现多线程的2种方式
(1)方式1:继承java.lang.Thread
package javase.jingjie.多线程;
/**
* 在java语言中实现多线程的第一种方式:
* 第一步: 继承java.lang.Thread;
* 第二步: 重写run方法
*
* 三个知识点:1.如何定义线程? 2.如何创建线程? 3.如何启动线程?
* */
import java.lang.*;
public class DuoXianCheng01 {
public static void main(String[] args) {
// 创建线程
Thread t=new Processor();
//启动
//这段代码执行瞬间结束,告诉JVM再分配一个新的栈给t线程
//run不需要程序员手动调用,系统线程启动之后自动调用run方法
t.start();
//t.run();//这是普通方法调用,这样做程序只有一个线程,run方法结束之后,下面程序才能继续执行。
//这段代码在主线程中运行
for(int i=0;i<10;i++) {
System.out.println("main-->"+i);
}
/*
* 有了多线程之后,main方法结束只是主线程栈中没有方法栈帧了。
* 但是其他线程或者其他栈中还有栈帧。
* main方法结束,程序可能还在运行。
* */
}
}
//定义一个线程
class Processor extends Thread{
//重写run方法
public void run() {
for(int i=0;i<100;i++) {
System.out.println("run-->"+i);
}
}
}
(2)方式2:写一个类实现java.lang.Runnable;接口
package javase.jingjie.多线程;
/**
* java中实现线程的第二种方法:
* -----第一步:写一个类实现java.lang.Runnable;接口
* -----第二步:实现run方法
* */
import java.lang.*;
public class DuoXianCheng02 {
public static void main(String[] args) {
// 创建线程
Thread t=new Thread(new Processor01());//Runnable t=new Processor01();
t.start();//启动
}
}
class Processor01 implements Runnable{
public void run() {
for(int i=0;i<10;i++) {
System.out.println("run-->"+i);
}
}
}
2. 7种线程的简单操作
(1) 三个方法:Thread.currentThread(), t.setName(""), t.getName()
package javase.jingjie.多线程;
/**
* 三个方法:
* 1.获取当前线程对象Thread.currentThread();currentThread()是一个静态方法,用类名去调用
* 2.给线程起名 t.setName( " 名字")
* 3.获取线程的名字 t.getName("");
*
* 多线程的结果:是不断变化的,哪个线程(主线程main,t1,t2)先抢到时间片,先启动运行该线程
* main
t2线程
Thread-0
main
Thread-0
t2线程
*
* */
public class DuoXianCheng03 {
public static void main(String[] args) {
// 获取当前线程对象,currentThread()是一个静态方法,用类名去调用
Thread t=Thread.currentThread();//t保存的内存地址指向的线程是“主线程对象”
//获取线程的名字
System.out.println(t.getName());//main
//创建线程,启动线程
Runnable p=new Processor02();
Thread t1=new Thread(p);
t1.start();
Thread t2=new Thread(new Processor02());
//给t2线程起名字
t2.setName("t2线程");
//启动线程
t2.start();
}
}
class Processor02 implements Runnable{
public void run() {
//当哪个(t1,t2)线程启动时,t就代表谁
Thread t=Thread.currentThread();//t保存的内存地址指向的线程是“t1、t2线程对象”
System.out.println(t.getName());//Thread-0 t2线程
}
}
(2)线程优先级
package javase.jingjie.多线程;
/**
* 线程优先级高的获取的CPU时间片相对多一些。
* 优先级:1~10 最低1, 默认5,最高10
* */
public class DuoXianCheng04 {
public static void main(String[] args) {
System.out.println(Thread.MAX_PRIORITY);
System.out.println(Thread.MIN_PRIORITY);
System.out.println(Thread.NORM_PRIORITY);
//多态,父类型指向子类型,子赋给父
Thread t1=new Processor03();
t1.setName("t1线程");
Thread t2=new Processor03();
t2.setName("t2线程");
//获取默认优先级 5
System.out.println(t1.getPriority());
System.out.println(t2.getPriority());
//设置优先级
t1.setPriority(5);
t2.setPriority(8);
//启动线程
t1.start();
t2.start();
}
}
class Processor03 extends Thread{
public void run() {
for(int i=0;i<50;i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
(3)Thread.sleep(毫秒),阻塞当前线程
package javase.jingjie.多线程;
/**
* 1.Thread.sleep(毫秒)
* 2.sleep方法是一个静态方法,用类名调用
* 该方法 的作用:阻塞当前线程,腾出CPU,让给其他线程
* */
public class DuoXianCheng05 {
public static void main(String [] args)throws Exception{
Thread t=new Processor04();
t.setName("t线程");
t.start();
//阻塞主线程
for(int i=0;i<10;i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
//sleep异常可以上抛到main方法,与run方法不同
//sleep()是一个静态方法,用类名去调用
Thread.sleep(500);//阻塞主线程0.5秒
}
//等同于类名. Thread.sleep(),还是主线程,等10秒输出hello World
t.sleep(10000);//编译用t调用,实际运行调用是Thread
System.out.println("hello World");
}
}
class Processor04 extends Thread{
//Thread中的run方法不抛出异常,所以重写run方法之后,在run方法声明的位置上不能使用throws
//所以只能用try catch语句块
public void run() {
for(int i=0;i<10;i++) {
//currentThread()是一个静态方法,用类名去调用
System.out.println(Thread.currentThread().getName()+"-->"+i);
try {
//编译异常语句,sleep()是一个静态方法,用类名去调用
Thread.sleep(1000);//让当前线程阻塞 1秒
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
(4) 打断线程的睡眠 t.interrupt();
package javase.jingjie.多线程;
/**
* 某线程正在睡眠,打断她的睡眠
* */
public class DuoXianCheng06 {
public static void main(String[] args) throws Exception{
//需求:启动线程,5秒之后打断线程的休眠
//第二种方法:实现接口方法的创建方式
Thread t=new Thread(new Processor05());
t.setName("t线程");
//启动run方法
t.start();
//主线程5秒之后,开始打断t线程的休眠
//此异常可以上抛,不在run()方法中
Thread.sleep(5000);
//打断t线程休眠
t.interrupt();
}
}
class Processor05 implements Runnable{
public void run() {
//run中的静态方法sleep()异常只能用try catch语句块处理
try {
//休眠
Thread.sleep(1000000000L);
//下面的代码不会输出,因为上面的语句是异常语句
System.out.println("Hello World");
}catch(InterruptedException e) {
//打印异常语句,可以不写该语句
e.printStackTrace();/*java.lang.InterruptedException: sleep interrupted
at java.base/java.lang.Thread.sleep(Native Method)
at javase.jingjie.多线程.Processor05.run(DuoXianCheng06.java:30)
at java.base/java.lang.Thread.run(Thread.java:835)*/
}
for(int i=0;i<10;i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
(5) 线程启动5秒之后终止,终止代码:p.run=false;
package javase.jingjie.多线程;
/**
* 需求:线程启动5秒之后终止
* */
public class DuoXianCheng07 {
public static void main(String[] args) throws Exception{
Processor06 p=new Processor06();
Thread t=new Thread(p);
t.setName("t");
t.start();
//5秒之后终止
Thread.sleep(5000);
//终止代码
p.run=false;
}
}
class Processor06 implements Runnable{
boolean run =true;
public void run() {
for(int i=0;i<10;i++) {
if(run) {
try {
Thread.sleep(1000);
}catch(Exception e) {}
System.out.println(Thread.currentThread().getName()+"-->"+i);
}else {
return;
}
}
}
}
(6) 同一优先级线程让位:Thread.yield();
package javase.jingjie.多线程;
/**
* Thread.yield();
* 1.该方法是一个静态方法。
* 2.作用:给同一个优先级的线程让位,但是让位时间不固定。
* 3.和sleep方法相同,就是yield时间不固定
* */
public class DuoXianCheng08 {
public static void main(String[] args) {
Thread t=new Processor07();
t.setName("t");
t.start();
//主线程中
for(int i=0;i<100;i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
class Processor07 extends Thread{
public void run() {
for(int i=0;i<100;i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
if(i%20==0) {
Thread.yield();
}
}
}
}
(7)线程的合并: t.join()
package javase.jingjie.多线程;
/**
* 线程的合并
* */
public class DuoXianCheng09 {
public static void main(String[] args) throws Exception{
Thread t=new Thread(new Processor08());
t.setName("t线程");
t.start();
//合并线程,t在哪个线程就合并哪个线程,成为单线程的程序
t.join();//t和主线程合并,有异常向上抛出
//主线程
for(int i=0;i<10;i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
class Processor08 implements Runnable{
public void run() {
for(int i=0;i<5;i++) {
try {
Thread.sleep(1000);
}catch(Exception e) {}
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
3. 线程锁机制:synchronized
锁机制(线程同步机制):synchronized关键词。
同步条件:(1)线程必须有共享对象(成员方法才有对象 );(2)在共享对象前提下,还要有共享数据;
- 1.当2个线程前面有synchronized,且2个线程共享当前对象/锁(this)时,谁先线程启动,并执行run,则第二个线程等待第一个归还锁(共享对象)后,开始启动执行共享对象;
- 2.同步机制总结就是:谁先synchronized谁先执行,第二个等待归还锁(当前共享对象this)后,接着执行;
- 3.线程不共享对象,即使2个都有synchronized,也不同步,即各自执行 ;
- 4.假如有一个没有synchronized,则不需要等待
(1) 成员方法的锁机制
package javase.jingjie.多线程;
public class DuoXianCheng10 {
public static void main(String[] args) throws Exception{
//mc作为共享对象,给几个线程(t1,t2)共享
MyClass mc=new MyClass();
Processor09 p=new Processor09(mc);
//p里面放着共享的mc对象
Thread t1=new Thread(p);
t1.setName("t1");
Thread t2=new Thread(p);
t2.setName("t2");
//启动线程
t1.start();
//延迟10s后,t2开始启动(保证t1线程先启动,并执行run)
Thread.sleep(500);
t2.start();
}
}
class Processor09 implements Runnable{
MyClass mc;
public Processor09(MyClass mc) {
this.mc=mc;
}
public void run() {
if(Thread.currentThread().getName().equals("t1")) {
mc.m1();
}
if(Thread.currentThread().getName().equals("t2")) {
mc.m2();
}
}
}
class MyClass{
public synchronized void m1() {
//休眠
try {
Thread.sleep(10000);
}catch(Exception e) {}
System.out.println("m1...");
}
/*m2方法的执行不需要等m1结束,因为m2方法上没有synchronized
public void m2() {
System.out.println("m2没有synchronized,不用等t1");
}
*/
//m2方法会等m1方法结束,t1、t2共享同一个mc,并且m1、m2方法上都有synchronized
public synchronized void m2() {
System.out.println("m2有synchronized,等t1");
}
}
(2) 类锁机制:静态方法的锁机制
package javase.jingjie.多线程;
/**
* 类锁:类只有一个,所以锁是类级别的,只有一个
* */
public class DuoXianCheng11 {
public static void main(String[] args) throws Exception{
Thread t1=new Thread(new Processor10());
Thread t2=new Thread(new Processor10());
t1.setName("t1");
t2.setName("t2");
//启动,执行run方法
t1.start();
//延迟,保证t1先执行
Thread.sleep(1000);//代表在主线程中延迟1s,之后执行t2
t2.start();
}
}
class Processor10 implements Runnable{
public void run() {
if("t1".equals(Thread.currentThread().getName())) {
MyClass01.m1();
}
if("t2".equals(Thread.currentThread().getName())) {
MyClass01.m2();
}
}
}
class MyClass01{
//synchronized添加到静态方法上,线程执行此方法的时候会找类锁
public synchronized static void m1() {
try {Thread.sleep(10000);}catch(Exception e) {}
System.out.println("m1....");
}
//不会等m1结束,因为该方法没有被synchronized修饰
/*
public static void m2() {
System.out.println("m2....");
}*/
//m2方法等m1结束后才能执行,该方法有synchronized,
//线程执行该代码需要“类锁”,而类锁只有一个
public synchronized static void m2() {
System.out.println("m2....");
}
}
(3)类锁机制:与静态锁有关,与对象锁无关,可以不共享对象
package javase.jingjie.多线程;
/**
* 类锁:类只有一个,所以锁是类级别的,只有一个.
*
* 注意:带有synchronized static即使不共享对象,也需要等,这是静态,与类锁有关,和对象锁无关
* */
public class DuoXianCheng12 {
public static void main(String[] args) throws Exception{
//带有synchronized static即使不共享对象,也需要等,这是静态,与类锁有关
MyClass02 mc1=new MyClass02();
MyClass02 mc2=new MyClass02();
Thread t1=new Thread(new Processor11(mc1));
Thread t2=new Thread(new Processor11(mc2));
t1.setName("t1");
t2.setName("t2");
//启动,执行run方法
t1.start();
//延迟,保证t1先执行
Thread.sleep(1000);//代表在主线程中延迟1s,之后执行t2
t2.start();
}
}
class Processor11 implements Runnable{
MyClass02 mc;
public Processor11 (MyClass02 mc) {
this.mc=mc;
}
public void run() {
if("t1".equals(Thread.currentThread().getName())) {
mc.m1();//mc底层用的还是类锁,和对象锁无关
}
if("t2".equals(Thread.currentThread().getName())) {
mc.m2();
}
}
}
class MyClass02{
//synchronized添加到静态方法(static )上,线程执行此方法的时候会找类锁
public synchronized static void m1() {
try {Thread.sleep(10000);}catch(Exception e) {}
System.out.println("m1....");
}
//不会等m1结束,因为该方法没有被synchronized修饰
/*
public static void m2() {
System.out.println("m2....");
}*/
//m2方法等m1结束后才能执行,该方法有synchronized,
//线程执行该代码需要“类锁”(static ),而类锁只有一个
public synchronized static void m2() {
System.out.println("m2....");
}
}
(4) 死锁
package javase.jingjie.多线程;
/**
* 死锁
* */
public class DuoXianCheng13 {
public static void main(String[] args) {
Object o1=new Object();
Object o2=new Object();
Thread t1=new Thread(new T1(o1,o2));
Thread t2=new Thread(new T2(o1,o2));
t1.start();
t2.start();
}
}
class T1 implements Runnable{
Object o1;
Object o2;
T1(Object o1,Object o2){
this.o1=o1;
this.o2=o2;
}
public void run() {
synchronized(o1) {
try {Thread.sleep(1000);}catch(Exception e) {}
synchronized (o2) {
}
}
}
}
class T2 implements Runnable{
Object o1;
Object o2;
T2(Object o1,Object o2){
this.o1=o1;
this.o2=o2;
}
public void run() {
synchronized(o2) {
try {Thread.sleep(1000);}catch(Exception e) {}
synchronized (o1) {
}
}
}
}
4. 守护线程和定时器
(1) 守护线程:t1.setDaemon(true)
package javase.jingjie.多线程;
/**
* 守护线程:
* 其他所有的用户线程结束,则守护线程退出!
* 守护线程一般是无限执行的
* */
public class DuoXianCheng14 {
public static void main(String[] args) throws Exception{
Thread t1=new Processor13();
t1.setName("t1");
//将t1这个用户线程修改成守护线程
t1.setDaemon(true);
t1.start();
//主线程
for(int i=0;i<10;i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
Thread.sleep(1000);
}
}
}
class Processor13 extends Thread{
public void run() {
int i=0;
//无线循环,但变成守护线程后,其他用户线程结束,则守护线程可以退出
while(true) {
i++;
System.out.println(Thread.currentThread().getName()+"-->"+i);
try {
Thread.sleep(500);
}catch(Exception e) {}
}
}
}
(2) 定时器的应用
package javase.jingjie.多线程;
/**
* 关于定时器的应用:
* 作用:每隔一段固定的时间执行一段代码
* */
import java.util.*;
import java.text.*;
public class DuoXianCheng15 {
public static void main(String[] args) throws Exception{
// 1.创建定时器
Timer t=new Timer();
//2.指定定时任务
t.schedule(new LogTimerTask(), //任务
new SimpleDateFormat("yyyy-MM-dd,HH:mm:ss:SSS").parse("2019-10-29,18:10:23:234"),//时间,parse字符串转日期
10*1000);//间隔时间
}
}
//指定任务
class LogTimerTask extends TimerTask{
public void run() {
//format-->将日期转化成字符串
System.out.println(new SimpleDateFormat("yyyy-MM-dd,HH:mm:ss:SSS").format(new Date()));
}
}