Day25-C:\Users\Lenovo\Desktop\note\code\JavaSE\Basic\src\com\Threadcase-多线程讲到等待唤醒机制的一半
多线程
进程
进程是程序的基本执行实体
线程
线程是操作系统能够进行运算调度的最小单位,它被包含在进程中,是进程中实际运行的基本单位
应用软件中相互独立,可以独立运行的功能
多线程就是同时运行多个子程序,提高效率
并发
在同一时刻,有多个指令在单个CPU上交替运行
并行
在同一时刻,有多个指令在多个CPU上同时运行
package Basic.src.com.Threadcase.Threadcase1;
public class MyThread extends Thread{
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"Hello,World");
}
}
}
package Basic.src.com.Threadcase.Threadcase1;
public class ThreadDemo {
/*
* 多线程的第一种启动方式:
* 1.定义一个类其继承thread类
* 2.重写里面的run方法
* 3.创建子类的对象,并启动线程
*
* */
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
//start()才表示开启线程
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
}
package Basic.src.com.Threadcase.Threadcase2;
public class MyRun implements Runnable{
private String name;
@Override
public void run() {
//书写线程需要的代码
for (int i = 0; i <100; i++) {
Thread t = Thread.currentThread();//getName方法得在Thread类里面找
System.out.println(t.getName()+"Hello World");
System.out.println(Thread.currentThread().getName()+"Hello World!");
}
}
}
package Basic.src.com.Threadcase.Threadcase2;
public class ThreadDemo {
/*
* 多线程的第二种启动方式:
* 1.自己定义一个类实现Runnable接口
* 2.重写里面的run方法
* 3.创建自己的类的对象
* 4.创建一个Thread类对象并开启线程
*
*
* */
public static void main(String[] args) {
//创建MyRun对象
//表示多线程要执行的任务
MyRun mr = new MyRun();
//创建线程对象
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
//线程设置名字
t1.setName("Thread1");
t2.setName("Thread2");
//开启线程
t1.start();
t2.start();
}
}
package Basic.src.com.Threadcase.Threadcase3;
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer> {//Integer是返回的结构的类型
@Override
public Integer call() throws Exception {
//求1~100之间的和
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
return sum;
}
}
package Basic.src.com.Threadcase.Threadcase3;
import Basic.src.com.Threadcase.Threadcase1.MyThread;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadDemo {
/*
* 多线程的第三种启动方式:
* 特点:可以获取到多线程运行的结构
* 1.自己定义一个MyCallable类实现Callable接口
* 2.重写里面的call方法,有返回值
* 3.创建自己的MyCallable类的对象
* 4.创建一个FutureTask类对象作用管理多线程运行的结果
*5.创建Thread类的对象,并启动(表示线程)
*
* */
public static void main(String[] args) throws ExecutionException, InterruptedException {
//3.创建自己的MyCallable类的对象,表示多线程要执行的任务
MyCallable mc = new MyCallable();
//4.创建一个FutureTask类对象作用管理多线程运行的结果
FutureTask<Integer> ft = new FutureTask<>(mc);
//5.创建Thread类的对象,并启动(表示线程)
Thread t1 = new Thread(ft);//public Thread(Runnable target)
//启动线程
t1.start();
//获取多线程
Integer res = ft.get();
System.out.println(res);
}
}
抢占式调度(与非抢占式调度区别)
抢占式调度:随机
具有优先级
package Basic.src.com.Threadcase.ThreadPriority;
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
Thread t = Thread.currentThread();
System.out.println(t.getName()+"---------"+i);
}
}
}
package Basic.src.com.Threadcase.ThreadPriority;
public class ThreadDemo {
public static void main(String[] args) {
//创建线程所要执行的参数对象
MyRunnable mr = new MyRunnable();
//创建线程对象
Thread t1 = new Thread(mr,"飞机");
Thread t2 = new Thread(mr,"坦克");
System.out.println(t1.getPriority());//默认优先级是5
System.out.println(t2.getPriority());
System.out.println(Thread.currentThread().getPriority());//5
//优先级越高抢到cpu的概率就越高
t1.setPriority(Thread.MIN_PRIORITY);
t2.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
}
}
守护线程
package Basic.src.com.Threadcase.DaemonThread;
public class MyThread1 extends Thread {
@Override
public void run() {
for (int i = 0; i <= 10; i++) {
System.out.println(getName()+"@"+i);
}
}
}
package Basic.src.com.Threadcase.DaemonThread;
public class MyThread2 extends Thread {
public void run() {
for (int i = 0; i <= 100; i++) {
System.out.println(getName()+"@"+i);
}
}
}
package Basic.src.com.Threadcase.DaemonThread;
import Basic.src.com.Threadcase.Threadcase1.MyThread;
public class ThreadDemo {
public static void main(String[] args) {
/*
* 当其他非守护线程执行结束后,守护线程也会陆续结束
* 当女神线程结束了,备胎也没有存在的必要
* */
MyThread1 t1 = new MyThread1();
MyThread2 t2 = new MyThread2();
t1.setName("女神");
t2.setName("备胎");
//把第二个线程设置为守护线程(备胎线程)
t2.setDaemon(true);
t1.start();
t2.start();
}
}
出让线程
package Basic.src.com.Threadcase.Threadyield;
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"@"+i);
//表示出让当前CPU的执行权
Thread.yield();//提高均匀度(一定程度上)
}
}
}
package Basic.src.com.Threadcase.Threadyield;
public class ThreadDemo {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.setName("飞机");
t2.setName("坦克");
t1.start();
t2.start();
}
}
插入线程
package Basic.src.com.Threadcase.ThreadJoin;
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"@"+i);
}
}
}
package Basic.src.com.Threadcase.ThreadJoin;
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
/*
*
* */
MyThread t = new MyThread();
t.setName("土豆");
t.start();
//把t线程插入到当前线程之前:当前main线程
t.join();
//执行在main线程中
for (int i = 0; i <= 10; i++) {
System.out.println("main"+i);
}
}
}
代码的生命周期
线程安全
同步代码块
package Basic.src.com.Threadcase.ThreadTicket;
public class MyThread extends Thread{
static int ticket = 0;//static表示这个类所有的对象共享ticket,不加会卖票300张
@Override
public void run() {
while (true) {
//同步代码块
synchronized (MyThread.class) {//锁对象一定要是唯一的
if (ticket < 100) {
try {
Thread.sleep(100);//睡眠时没有CPU执行权,会被其他线程抢走
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
ticket++;
System.out.println(getName()+"正在卖票第"+ ticket+"张票!!");
}else{
break;
}
}
}
}
}
package Basic.src.com.Threadcase.ThreadTicket;
public class ThreadDemo {
public static void main(String[] args) {
/*
* 需求:某电影院正在上映国产大片,一共有100张票,而他有三个窗口卖,请设计一个程序模拟电影院卖票
* */
//创建线程对象
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
//起名字
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
//开启线程
t1.start();
t2.start();
t3.start();
}
}
同步方法
package Basic.src.com.Threadcase.ThreadSafe.ThreadTicket1;
public class MyRunnable implements Runnable {
int ticket = 0;
@Override
public void run() {
//1.循环
//2.同步代码块(同步方法)
//3.判断共享数据是否到了末尾,如果到了末尾
//4.判断共享数据是否到了末尾,如果没有到末尾
while (true) {
if (method()) break;
}
}
//ctrl+alt+M
//this默认(非静态),此时是唯一的,因为MyRunnable只实现了一次
private synchronized boolean method() {
//达到末尾
if (ticket == 100) {
return true;
}
//没有达到末尾
else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket++;
System.out.println(Thread.currentThread().getName()+"在卖第"+ticket+"张票");
}
return false;
}
}
package Basic.src.com.Threadcase.ThreadSafe.ThreadTicket1;
public class ThreadDemo {
/*
* 需求:某电影院正在上映国产大片,一共有100张票,而他有三个窗口卖,请设计一个程序模拟电影院卖票
* 利用同步方法完成
* 技巧:同步代码块
* */
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
Thread t3 = new Thread(mr);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
StringBuilder和StringBuffer
StringBuilder非线程安全
StringBuffer线程安全
Lock锁
是接口不能直接实例化,可以采用它的实现类ReentrantLock来实例化
package Basic.src.com.Threadcase.ThreadSafe.Lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyThread extends Thread {
static int ticket = 0;
static Lock lock = new ReentrantLock();//Lock是接口不能直接实例化
//必须加上static关键字在lock前面,否则就是三个对象三把锁
//如果锁对象不声明为 static,则它是实例成员变量—— 每个类的实例会拥有独立的锁对象。
// 此时,不同实例的线程会持有不同的锁,无法实现跨实例的同步,导致同步失效。
@Override
public void run() {
while (true) {
//同步代码块,不能写在循环外面,否则会一直是一个窗口抢票
//synchronized (Basic.src.com.Threadcase.ThreadSafe.Lock.MyThread.class) {//锁对象一定要是唯一的。MyThread.class表示当前类的字节码文件对象
lock.lock();//上锁与synchronized重复
try {
if (ticket == 100) {
break;//break会跳过unlock,
}
//没有达到末尾
else {
Thread.sleep(100);
ticket++;
System.out.println(Thread.currentThread().getName()+"在卖第"+ticket+"张票");
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {//finally里面保证了锁一定被释放
lock.unlock();//开锁
}
//}
}
}
}
package Basic.src.com.Threadcase.ThreadSafe.Lock;
import Basic.src.com.Threadcase.ThreadSafe.ThreadTicket1.MyRunnable;
public class ThreadDemo {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
死锁
是一个错误
指的是锁的嵌套
package Basic.src.com.Threadcase.ThreadSafe.DeadLock;
public class MyThread extends Thread{
static Object objA = new Object();
static Object objB = new Object();
@Override
public void run() {
while(true){
if("线程A".equals(Thread.currentThread().getName())){
synchronized (objA){
System.out.println("线程A拿到了A锁,准备拿B锁");
synchronized (objB){
System.out.println("线程A拿到了B锁,顺利执行完一轮");
}
}
} else if ("线程B".equals(Thread.currentThread().getName())) {
synchronized (objB){
System.out.println("线程B拿到了B锁,准备拿A锁");
synchronized (objA){
System.out.println("线程B拿到了A锁,顺利执行完一轮");
}
}
}
}
}
}
package Basic.src.com.Threadcase.ThreadSafe.DeadLock;
public class ThreadDemo {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.setName("线程A");
t2.setName("线程B");
t1.start();
t2.start();
}
}
等待唤醒机制
生产者和消费者
未讲完

浙公网安备 33010602011771号