基础_Java多线程

1.Thread

public class Demo1 {
	public static void main(String[] args) {
		MyThred m = new MyThred();//新建线程子对象
		m.start();	//开启线程,执行run方法
		
		for (int i = 0; i < 10000; i++) {
			System.out.println("aaaaaaaaaaaaaaaaaaaaa");
		}
	}
}
//继承Thread类
class MyThred extends Thread {
	@Override
	public void run() { //重写run方法
		for (int i = 0; i < 10000; i++) {
			System.out.println("线程");
		}
	}
}

好处 : 可以直接使用Thread类中的方法 代码简单
弊端 : 如果已经有了父类 就不能使用这种方法 (java单继承)

2.创建实现runable方法 创建线程

public class demo_runable {
	public static void main(String[] args) {
		myRunnable mr = new myRunnable();//Runable是接口 
		Thread t = new Thread(mr); 
		t.start();
		
		for (int i = 0; i < 10000; i++) {
			System.out.println("aaaaaaaaaaa");
		}
	}
}
//实现runnable接口
class myRunnable implements Runnable {
	@Override
	public void run() {
		// TODO Auto-generated method stub
		for (int i = 0; i < 10000; i++) {
			System.out.println("线程");
		}
	}
}


编译看父类 运行看子类

runable源码:
 //1   
 public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);}
//2       
this.target = target;   局部变量 赋给成员变量
//3 
 @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }    

构造函数中传入了Runable的引用 成员变量记住了她 start调用run方法时
内部判断成员变量是否为空 执行子类的Run方法

好处 : 即使自己定的的线程有了父类也没有关系 因为有了父类 也可以实现接口 而且接口是可以多实现的
弊端 : 不能直接使用Thread的方法 需要先获取到线程对象后 才能得到Thread方法 代码复杂

new class(){} 继承这个类

3.Callable (重写call方法 能抛异常 有返回值)


匿名内部类 :

没有具体的类名 直接使用new class

public class demo_noName {
	public static void main(String[] args) {
     
		new Thread() {
			@Override
			public void run() {
				for (int i = 0; i < 10000; i++) {
					System.out.println("bb");
				}
			}
		}.start();

		new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10000; i++) {
					System.out.println("aaaaaaaaaaaaaaa");
				}
			}
		}).start();
	}
}

获取修改线程名字 this.getName()
修改有两种 :

  1. 构造方法修改 直接传String
  2. this.setName(“String”)

获取当前线程对象 :

public class demo_current {
	public static void main(String[] args) {
		
		new Thread("String") {
			@Override
			public void run() {
				System.out.println(getName());
			}
		}.start();

		new Thread(new Runnable(){
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());
			}
		}).start();
		//获取正在执行的线程对象
		System.out.println(Thread.currentThread().getName());
	}
} 

sleep

try {
    Thread.sleep(1000); //毫秒 1s = 1000ms
} catch (InterruptedException e) {
    e.printStackTrace();
}

守护线程 setDaemon :

相当于象棋里的 车马炮 非守护线程就是 帅

public class demo_setDaemon {
	public static void main(String[] args) {

		Thread t1 = new Thread() {
			public void run() {
				for (int i = 0; i < 1; i++) {
					System.out.println(getName() + "...aaaaaaaaaaaaaa" + i);
				}
			}
		};
		Thread t3 = new Thread() {
			public void run() {
				for (int i = 0; i < 3; i++) {
					System.out.println(getName() + "...qqqqqqqqqqqqqqq" + i);
				}
			}
		};
		Thread t2 = new Thread() {
			public void run() {
				for (int i = 0; i < 100; i++) {
					System.out.println(getName() + "...b" + i);
				}
			}
		};
		t2.setDaemon(true);
		t3.start();
		t1.start();
		t2.start();
	}
}

加入线程(当前线程暂停 , 等待指定的线程执行结束后 当前线程再继续)

public class demo_join {
	public static void main(String[] args) {
		final Thread t1 = new Thread() {      //final
			public void run() {
				for (int i = 0; i < 100; i++) {
					System.out.println(getName() + "...aaaaaaaaaaaaaa" + i);
				}
			}
		};

		Thread t2 = new Thread() {
			public void run() {
				for (int i = 0; i < 10; i++) {
					try {
						t1.join(1);  //占有时间ms
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(getName() + "...b" + i);
				}
			}
		};
		t2.start();
		t1.start();
	}
}

礼让线程 : yield

设置线程的优先级 ; setPriority(Thread.MAX_) //直接整数字也可

匿名内部类 使用局部变量 要用final修饰
同步代码块 : synchronized关键字 (🔒) //锁机制 锁对象可以是任意的 !!锁对象不能用匿名对象

public class demo_clock {
	public static void main(String[] args) {
		final Printer p = new Printer();
		new Thread() {
			@Override
			public void run() {
				for (int i = 0; i < 100; i++) {
					p.print1();
				}
			}
		}.start();

		new Thread() {
			@Override
			public void run() {
				for (int i = 0; i < 100; i++) {
					p.print2();
				}
			}
		}.start();
	}
}

class Printer {
	Demo d = new Demo();

	public void print1() {
		synchronized (d) {
			System.out.print("你");
			System.out.print("好");
			System.out.print("啊");
			System.out.print("xin");
			System.out.print("yue");
			System.out.println("\r");
		}
	}

	public void print2() {
		synchronized (d) {
			System.out.print("lee");
			System.out.print("s");
			System.out.println("\r");
		}
	}
}

class Demo {  //任意对象

}

同步方法 :

非静态的同步方法的锁对象是什么? this
静态的同步方法的锁对象是什么? 该类的字节码对象

class Printer{
    public synchronized void print1() {  //static
            System.out.print("你");
       	System.out.print("好");
    	System.out.print("啊");
    	System.out.print("xin");
    	System.out.print("yue");
    	System.out.println("\r");
     }
    
    public void print2() {
    	synchronized (this) {        //Printer.class
      		System.out.print("lee");
    		System.out.print("s");
    		System.out.println("\r");
    	}
    }
}

线程安全问题 :

//一百张票  4个窗口同时卖

public class demo_demo {
	public static void main(String[] args) {
		new Ticket().start();
		new Ticket().start();
		new Ticket().start();
		new Ticket().start();
	}
}
class Ticket extends Thread {
	private static int ticket = 1000; //注意 static
	@Override
	public void run() {
		while (true) {
			synchronized (Ticket.class) {  //字节码对象
                                         //不能是this 因为创建了四个对象                           
				if (ticket == 0)
					break;
				try {
					Ticket.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(getName() + "第" + ticket-- + "号票");
			}
		}
	}
}  

a. 线程0来的时候 遇到 ==0 睡了 ; 线程1来 ==0 睡了 ; 线程2 来 睡了 ; 线程3 来 睡了 ;
然后 线程0苏醒 .执行 - - ; 线程1 苏醒 执行 - - ; …就会出现负值
b. 不加static 每个Ticket对象 都有一个ticket
c. 如果用引用数据类型成员变量当作锁对象 , 必须是静态的

//Runnable 实现
public class demo_demo2 {
	public static void main(String[] args) {
		Tickets t = new Tickets();
		new Thread(t).start();
		new Thread(t).start();
		new Thread(t).start();
		new Thread(t).start();
	}//创建了一个对象当参数 传入Thread 开启四个线程
}   //.start() 四次非法
class Tickets implements Runnable {
    private int tickets = 100;
    @Override
	public void run() {
		while (true) {    
			synchronized (this) {   //this !!!!

				if (tickets == 0)
					break;
				try {
					Ticket.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "第"
						+ tickets-- + "号票");
			}
		}
	}
} 

单例设计模式(掌握)

保证类在内存中只有一个对象

//饿汉式
class Singleton {
	//1.私有构造方法 其他类就不能访问了
	private Singleton() {
	}
	//2.创建本类对象
	private static Singleton s = new Singleton();
	//3.对外提供访问方法
	public static Singleton getInstance(){ //获取实例
		return s;	
	}
}

//懒汉式 , 单例的延迟加载模式
class Singleton{
	//1.私有构造方法 其他类就不能访问了
		private Singleton() {
		}
		//2.创建本类对象
		private static Singleton s ;
		//3.对外提供访问方法
		public static Singleton getInstance(){ //获取实例
			if (s == null) {
				//线程1等待 线程2等待
				s = new Singleton();
			}
			return s;	
		}
}

饿汉式 懒汉式区别

1.饿汉式是空间换时间 懒汉式是时间换空间
2.在多线程访问时 懒汉式不会创建多个对象 而懒汉式有可能会创建多个对象

//第三种
public class duo_single {
	public static void main(String[] args) {
		Singleton s1 = Singleton.s;
		Singleton s2 = Singleton.s;
		System.out.println(s1 == s2);
	}
}
class Singleton{
	//1.私有构造方法 其他类就不能访问了
		private Singleton() {
		}
		//2.声明一个引用
		public static final Singleton s = new Singleton();
}

Runtime类(单例)

Runtime r = Runtime.getRuntime();  //获取运行时对象
r.exec("shutdown -s -t 300");

Timer类 :计时器

public class duo_timer {
	public static void main(String[] args) throws InterruptedException {
		Timer  t = new Timer();
		//指定时间安排指定任务
		t.schedule(new MyTimeTask(), new Date(120, 2, 2, 22, 53, 30));
		while(true){
			Thread.sleep(1000);
			System.out.println(new Date());
		}
	}
}

class MyTimeTask extends TimerTask{
	@Override
	public void run() {
		System.out.println("起床背英语");
	}
}

两个线程间通信(掌握) :

等待唤醒机制 wait notify[All]

public class duo_Tongxin {
	public static void main(String[] args) {
		final Printer1 p = new Printer1();
		new Thread(){
			public void run() {
				while(true){
					try {
						p.print1();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
		}.start();
		
		new Thread(){
			public void run() {
				while(true){
					try {
						p.print2();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
		}.start();
	}
}
class Printer1{
	private int flag = 1;
	public void print1() throws InterruptedException {
		synchronized (this) {
			if (flag!=1) {
				this.wait();
			}
			System.out.print("明");
			System.out.print("天");
			System.out.print("你");
			System.out.print("好");
			System.out.println();
			flag=2;
			this.notify();
		}
	}
	public void print2() throws InterruptedException {
		synchronized (this) {
			if (flag!=2) {    //
				this.wait();
			}
			System.out.print("a");
			System.out.print("b");
			System.out.print("c");
			System.out.print("d");
			System.out.println();
			flag = 1;
			this.notify();   //
		}
	}
}

三个以上线程通信
判断flag时 改成while ; 每次都判断
唤醒 要改成 notifyAll()

线程间通信注意的问题 :
在同步代码块中 用哪个对象锁 就用哪个对象调用wait方法
为什么wait方法和notify方法定义在Object这个类中?
因为锁对象可以是任意对象 Object是所有 类的父类 , 所以wait方法 和notify
sleep 和 wait方法区别
a. sleep必须传入参数 参数就是时间 时间到了自动醒来
wait方法 可以传入参数 也可以不传入参数 ,传入参数就是在参数时间结束后等待
b.sleep方法在同步函数或同步代码块中 不释放锁
wait方法在同步函数或同步代码块中 释放锁

1.5新特性

互斥锁(掌握) : ReentrantLock Condition
可以指定唤醒 因此不用while 用if 即可 ;

public class duo_Lock {
	public static void main(String[] args) {
		final Printer2 p = new Printer2();
		new Thread(){
			public void run() {
				while (true) {
					try {
						p.print1();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
		}.start();
		
		new Thread(){
			public void run() {
				while (true) {
					try {
						p.print2();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
		}.start();
		
		new Thread(){
			public void run() {
				while (true) {
					try {
						p.print3();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
		}.start();
	}
}
class Printer2{
	private ReentrantLock r = new ReentrantLock();
	private Condition c1 = r.newCondition();
	private Condition c2 = r.newCondition();
	private Condition c3 = r.newCondition();
	private int flag = 1;
	public void print1() throws InterruptedException {
		
		r.lock();      		//替换synchronized
			if (flag!=1) {
				c1.await();//this.wait();
			}
			System.out.print("明");
			System.out.print("天");
			System.out.print("你");
			System.out.print("好");
			System.out.println();
			flag=2;
			c2.signal();		//this.notifyAll();
		r.unlock();
	}
	public void print2() throws InterruptedException {
		r.lock();
			if (flag!=2) {
				c2.await();//this.wait();
			}
			System.out.print("a");
			System.out.print("b");
			System.out.print("c");
			System.out.print("d");
			System.out.println();
			flag = 3;
			c3.signal();//this.notifyAll();
		r.unlock();
	}
	public void print3() throws InterruptedException {
		r.lock();
			while (flag!=3) {
				c3.await();//this.wait();
			}
			System.out.print("v");
			System.out.println();
			flag = 1;
			c1.signal();//this.notifyAll();
		r.unlock();
	}
}

多线程组的概述和使用: ThreadGroup

public class duo_group {
	public static void main(String[] args) {
		ThreadGroup tg = new ThreadGroup("线程组"); //创建新的线程组
		myRunable my = new myRunable();				//创建Runnable的子类对象
		
		Thread t1 = new Thread(tg, my, "李顺");   //将线程放在组中
		Thread t2 = new Thread(tg, my, "lee");
		System.out.println(t1.getThreadGroup().getName());
		System.out.println(t2.getThreadGroup().getName());
		
		tg.setDaemon(true);  //真个组 设置成守护线程
	}
}

线程的五种状态 :

在这里插入图片描述

线程池的概述 : 省得 创建死亡过程 (尤其是创建短的线程)

所以 每一个线程结束后并不会死亡 而是回到线程池中成为空闲状态
ExecutorService

public class duo_chi {
	public static void main(String[] args) {
		ExecutorService pool = Executors.newFixedThreadPool(2);//创建线程池
		pool.submit(new myRunable());		//将线程放进池子里并执行
		pool.submit(new myRunable());
		
		pool.shutdown();  //关闭线程池
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bruce.vvu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值