多线程
自定义线程类继承Thread类
重写run方法,编写线程执行体
创建线程对象,调用start()方法启动线程。
package com.wang.threads;
/**
* @author valive
* @create 2021-04-14 15:56
**/
public class TestThread1 extends Thread {
@Override
public void run(){
//run方法线程体
for (int i = 0; i < 20; i++) {
System.out.println("你好"+i);
}
}
public static void main(String[] args) {
//main线程,主线程
TestThread1 testThread1 =new TestThread1();
testThread1.run();
for (int i = 0; i < 20; i++) {
System.out.println("我在看电视"+i);
}
}
}
run方法先执行run(),完了再走主路径。只有主线程一条执行路径
start方法有多条执行路径,主线程和子线程同时执行。
线程开启不一定立即就执行,看CPU调度。
继承Thread类
- 子类继承Thread类具备多线程能力
- 启动线程:子类对象.start()
- 但是不建议使用这种:避免oop单继承局限性
实现Runnable接口
- 实现接口Runnable具有多线程能力
- 启动线程:传入目标对象+Thread对象.start()
- 推荐使用,避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
package com.wang.threads;
/**
* @author valive
* @create 2021-04-14 19:43
**/
public class TestThread2 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("你好"+i);
}
}
public static void main(String[] args) {
TestThread2 testThread2 =new TestThread2();
new Thread(testThread2).start();
for (int i = 0; i < 1000; i++) {
System.out.println("世界"+i);
}
}
}
模拟龟兔赛跑
package com.wang.threads;
/**
* @author valive
* @create 2021-04-14 20:04
**/
public class Race implements Runnable{
//胜利者
private static String winner;
@Override
public void run(){
for (int i = 0; i <= 100; i++) {
//模拟兔子休息
if (Thread.currentThread().getName().equals("兔子")&&i%10==0){
try {
Thread.sleep(5);
}catch (InterruptedException e){
e.printStackTrace();
}
}
boolean flag=gameOver(i);
//如果比赛结束就停止程序
if (flag){
break;
}
System.out.println(Thread.currentThread().getName()+"--》跑了"+i+"步");
}
}
private boolean gameOver(int steps){
//判断是否有胜利者
if (winner!=null){//存在胜利者
return true;
}{
if (steps>=100){
winner=Thread.currentThread().getName();
System.out.println("winner is "+winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
Race race=new Race();
new Thread(race,"兔子").start();
new Thread(race,"乌龟").start();
}
}
静态代理模式
- 真实对象和代理对象都要实现同一个接口
- 代理对象要代理真实角色
- 好处是代理对象可以做很多真实对象做不来的,真实对象可以专注做自己的事情
package com.wang.threads;
/**
* @author valive
* @create 2021-04-15 14:54
**/
public class StaticProxy {
public static void main(String[] args) {
new Thread(()-> System.out.println("我爱你")).start();
You you =new You();
WeddingCompany weddingCompany =new WeddingCompany(new You());
weddingCompany.HappyMarry();
}
}
interface Marry{
void HappyMarry();
}
//真实角色,你去结婚
class You implements Marry{
@Override
public void HappyMarry(){
System.out.println("结婚");
}
}
//代理角色,帮助你结婚
class WeddingCompany implements Marry{
//代理谁-->真实目标角色
private Marry target;
public WeddingCompany(Marry target){
this.target=target;
}
@Override
public void HappyMarry(){
before();
this.target.HappyMarry();//真实对象调用的结婚
after();
}
private void after(){
System.out.println("结婚后睡觉");
}
private void before(){
System.out.println("结婚之前布置现场");
}
}
Lambda表达式
用处是避免匿名内部类定义过多,能使代码更加简洁;其实质属于函数式编程的概念。
任何接口,如果只包含唯一一个抽象方法,那么他就是函数式接口
package com.wang.threads;
/**
* 推导lamda表达式
*/
/**
* @author valive
* @create 2021-04-15 15:46
**/
public class TestLambada1 {
//静态内部类
static class Like2 implements ILikce{
@Override
public void lambda(){
System.out.println("lambda2");
}
}
public static void main(String[] args) {
ILikce like =new Like();
like.lambda();
like =new Like2();
like.lambda();
//局部内部类
class Like3 implements ILikce {
@Override
public void lambda() {
System.out.println("lambda3");
}
}
like =new Like3();
like.lambda();
//匿名内部类,没有类名,必须借助接口或者父类
like =new ILikce(){
@Override
public void lambda() {
System.out.println("lambda4");
}
};
like.lambda();
//用lambda简化
like = ()-> {
System.out.println("lambda5");
};
like.lambda();
//lambda表达式,只能有有一行代码的情况下才能简化为一行,多行只能简化到代码块。
like=()->System.out.println("lambda6");
like.lambda();
}
}
//定义一个函数式接口
interface ILikce{
void lambda();
}
//实现类
class Like implements ILikce{
@Override
public void lambda(){
System.out.println("lambda");
}
}
sleep实现线程的休眠
package com.wang.sleep;
/**
* @author valive
* @create 2021-04-17 13:51
**/
public class testSleep {
public static void main(String[] args) {
try {
tenDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void tenDown() throws InterruptedException{
int num = 10;
while (true){
Thread.sleep(1000);
System.out.println(num--);
if (num<=0){
break;
}
}
}
}
礼让yield
package com.wang.sleep;
import com.sun.org.apache.bcel.internal.generic.NEW;
/**
* @author valive
* @create 2021-04-17 13:55
**/
//礼让不一定成功,看CPU情况
public class TestYield {
public static void main(String[] args) {
MyYield myYield=new MyYield();
new Thread(myYield,"a").start();
new Thread(myYield,"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run(){
System.out.println(Thread.currentThread().getName()+"开始");
Thread.yield();//礼让
System.out.println(Thread.currentThread().getName()+"end");
}
}
join,线程强制执行
合并线程,待该线程执行完成了,再执行其他的线程,其他线程阻塞;尽量不使用。
package com.wang.sleep;
/**
* @author valive
* @create 2021-04-17 14:05
**/
public class TestJoin implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("线程VIP来了"+i);
}
}
public static void main(String[] args) throws InterruptedException {
TestJoin testJoin =new TestJoin();
Thread thread=new Thread(testJoin);
thread.start();
//主线程
for (int i = 0; i < 400; i++) {
if (i==200){
thread.join();
}
System.out.println("main"+i);
}
}
}
守护线程
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕。
package com.wang.sleep;
/**
* @author valive
* @create 2021-04-17 14:48
**/
public class TestDaemon {
public static void main(String[] args) {
God god=new God();
You you=new You();
Thread thread=new Thread(god);
thread.setDaemon(true);//默认是false,表示是用户线程,正常的线程都是用户线程
thread.start();//启动神守护线程
new Thread(you).start();
}
}
class God implements Runnable{
@Override
public void run() {
while (true){
System.out.println("神保护着你");
}
}
}
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("天天开心");
}
System.out.println("离开了世界");
}
}
同步方法和同步块
可以通过private关键字来保证数据对象只能被方法访问,所以我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,包含synchronized方法和synchronize块。
方法执行就独占一个锁,直到方法返回释放,后面被阻塞的线程才能获得这个锁,继续执行。
缺点是 :如果将一个大的方法申明为synchronized会影响效率。
同步块:synchronized(Obj){}
Obj为同步监视器,可以为任何对象,但是推荐使用共享资源作为同步监视器。
同步方法无需指定同步监视器,因为同步方法的同步监视器就是this ,就是这个对象本身。
避免死锁
package com.wang.lock;
/**
* @author valive
* @create 2021-04-17 16:38
**/
//多个线程互相拥有对方需要的资源,然后形成了僵持
public class DeafLock {
public static void main(String[] args) {
Mackup g1=new Mackup(0,"bluer");
Mackup g2=new Mackup(0,"reds");
g1.start();
g2.start();
}
}
class Lipstick{
}
class Mirror{
}
class Mackup extends Thread {
//用static保证只有一份资源
static Lipstick lipstick = new Lipstick();
static Mirror mirror = new Mirror();
int choice;
String girlName;
Mackup(int choice, String girlName) {
this.choice = choice;
this.girlName = girlName;
}
@Override
public void run() {
//化妆
try {
makeup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void makeup() throws InterruptedException {
if (choice == 0) {
synchronized (lipstick) {//获得口红的锁
System.out.println(this.girlName + "获得口红锁");
Thread.sleep(1000);
}
synchronized (mirror) {//一秒后获得镜子的锁
System.out.println(this.girlName + "获得镜子的锁");
}
}
else{
synchronized (mirror) {//一秒后获得镜子的锁
System.out.println(this.girlName + "获得镜子的锁");
Thread.sleep(2000);
}
synchronized (lipstick) {//获得口红的锁
System.out.println(this.girlName + "获得口红锁");}
}
}
}