### 并行和并发
并行: 同一时刻,多个程序同时执行
并发: 同一时间段,多个程序交替执行
1.分时调度:
为每个线程分配相同的执行时间
2.抢占式调度:
CPU优先执行优先级别高的线程,多个相同优先级的线程,CPU就随机选择一个执行
### 主线程----------至少有一个线程,用于执行main方法中的代码,称为主线程/main线程
## 线程的创建Thread类
1.定义类继承Thread类
2.Thread类的子类覆盖重写run方法
3.创建Thread类的子类对象
4.Thread类的子类对象调用start方法,开启线程
1.开启线程必须调用start方法,不能直接调用run方法
如果调用run方法没有多线程的执行效果
2.多线程程序运行结果具有随机性
获取线程名称:
1.Thread类的成员方法
getName(): 返回该线程的名称。 setName(String name): 设置该线程的名称。
public Thread(String name): 通过构造方法指定线程名称
2.如何获取main线程的名称呢? 静态方法 static Thread currentThread(): 返回对当前正在执行的线程对象,此方法currentThread在哪个线程中执行,获取到的就是那个线程对象
3静态方法: static sleep(long millis): 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
第一种
//Thread的子类
public class SubThread03 extends Thread {
public SubThread03(String name) {
super(name);
}
@Override
public void run() {
//获取线程名称
//String threadName = super.getName();
String threadName = Thread.currentThread().getName();
for (int i = 0; i < 10; i++) {
System.out.println(threadName+"..."+i);
}
}
}
//测试类
public class Demo03Thread {
public static void main(String[] args) {
/*SubThread03 t1 = new SubThread03();
SubThread03 t2 = new SubThread03();
SubThread03 t3 = new SubThread03();
//修改线程名称
t1.setName("张三");
t2.setName("李四");
t3.setName("王五");*/
SubThread03 t1 = new SubThread03("zs");
SubThread03 t2 = new SubThread03("ls");
SubThread03 t3 = new SubThread03("ww");
t1.start();
t2.start();
t3.start();
//因为currentThread方法是在main线程中执行
//返回的main线程对象
Thread mainThread = Thread.currentThread();
System.out.println("--------------------------main线程名称: "+mainThread.getName());
}
}
//测试类
public class Demo04Sleep {
public static void main(String[] args) throws InterruptedException {
//模拟发射火箭
for (int i = 10; i >= 1; i--) {
Thread.sleep(1000);
System.out.println(i);
}
System.out.println("发射....");
}
}
第二钟
1.定义实现类,实现Runnable接口new Thread(task);
2.实现类覆盖重写Runnable接口抽象方法run
3.创建Runnable接口的实现类对象
4.创建Thread线程对象,构造方法传递Runnable接口的实现类对象
5.Thread线程对象调用start方法,开启线程
好处 1.避免extend thread java类的单继承的局限性
2.降低了线程对象和线程任务对象的耦合性
耦合性: 事物与事物之间的关系
高内聚,低耦合
3.可以实现多个线程共享一个任务
//定义Runnalbe接口实现类
public class MyRunnable04 implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName()+"....."+i);
}
}
}
//测试类
public class Demo05Thread {
public static void main(String[] args) {
//3.创建Runnable接口的实现类对象
MyRunnable04 task = new MyRunnable04();
//4.创建Thread线程对象,构造方法传递Runnable接口的实现类对象
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
Thread t3 = new Thread(task);
//5.Thread线程对象调用start方法,开启线程
t1.start();
t2.start();
t3.start();
}
}
//测试类
public class Demo06Thread {
public static void main(String[] args) {
//3.创建Runnable接口的实现类对象
//只是创建线程任务对象,不是线程对象(没有继承Thread类)
MyRunnable04 task = new MyRunnable04();
//4.创建Thread线程对象,构造方法传递Runnable接口的实现类对象
//只是创建一个线程对象,需要执行什么任务,通过构造方法传递过来
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
Thread t3 = new Thread(task);
//5.Thread线程对象调用start方法,开启线程
t1.start();
t2.start();
t3.start();
}
}
第三种匿名内部类方式创建线程
作用: 创建子类/实现类对象的快捷方式
格式:
new 抽象父类/接口(){
覆盖重写所有的抽象方法
}
含义: 1.该对象没有名字 2.该对象所属的类没有名字
(底层: JVM根据抽象类/接口,帮助我们创建一个子类/实现类,并生成构造方法)
public class Demo05Thread {
public static void main(String[] args) {
//1.匿名内部类方式创建线程: 单独创建创建Runnable接口的实现类对象和线程对象
//多态创建Runnable接口的实现类对象
Runnable task1 = new Runnable() {
@Override
public void run() {
System.out.println("线程任务A...");
}
};
//创建线程对象,传递Runnable接口的实现类对象
Thread t1 = new Thread(task1);
//线程对象调用start方法开启线程
t1.start();
//2.匿名内部类方式创建线程: 单独创建Thread对象,传递Runnable接口的实现类对象
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程任务B...");
}
});
t2.start();
//3.匿名内部类方式创建线程: 直接创建Thread对象并开启线程,传递Runnable接口的实现类对象
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程任务C...");
}
}).start();
}
}
##使用同步代码块方式解决多线程操作共享数据问题 3个线程共同销售100张电影票
使用同步技术 保证操作共享数据的多条语句,要么全部执行,要么全部都不执
同步代码块 格式:
synchronized(任意对象) {
...
}
2.注意:
(1)所有操作共享数据的代码必须写在{}中
(2)任意对象: 锁对象/对象锁,专业术语对象监视器
(3)锁对象可以是任意对象,但是必须要保证唯一
同步方法 格式: 修饰符 synchronized 返回值类型 方法名称(参数列表...){
方法体代码
}
(1)所有操作共享数据的代码必须写在{}中
(2)同步方法不能自己指定锁对象
(3)非静态同步方法而言: 锁对象,必须有: this
静态同步方法内部锁对象: 静态方法所在类的Class对象MySellTicketTask03.class
//创建Runnable接口的实现类
public class MySellTicketTask02 implements Runnable {
//多个线程共享的数据
private int num = 100;
//锁对象可以是任意对象,但是必须要保证唯一
//因为MySellTicketTask02的对象只有一个
//成员lock只有一份,保证了唯一
private Object lock = new Object();
@Override
public void run() {
//int num = 100;//100张票被三个线程共享使用
//死循环
while(true) {
//同步代码块
//synchronized (new Object()) {//Object对象作为锁对象,会出现3个
//synchronized (lock) {
synchronized (this) {//this代表调用run方法的对象task,而task只有一个
//(1)判断是否有票
if (num > 0) {
//(2)有票: 打印输出一张票
//模拟出票的时间
try {Thread.sleep(100);}catch (Exception e){e.printStackTrace();}
String threadName = Thread.currentThread().getName();
System.out.println(threadName+"卖出第 "+num+" 张票...........");
//(3)票的数量减少1张
num--;
}
}
}
}
}
//测试类
public class Demo02Tickets {
public static void main(String[] args) {
//3.创建Runnable接口的实现类的对象,线程任务对象
MySellTicketTask02 task = new MySellTicketTask02();
//4.创建3个线程对象,构造方法发传递线程任务对象
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
Thread t3 = new Thread(task);
//5.这3个线程对象分别调用start方法,开启线程
t1.start();
t2.start();
t3.start();
}
}
同步方法
//创建Runnable接口的实现类
public class MySellTicketTask03 implements Runnable {
//多个线程共享的数据
private int num = 100;
//锁对象可以是任意对象,但是必须要保证唯一
//因为MySellTicketTask02的对象只有一个
//成员lock只有一份,保证了唯一
private Object lock = new Object();
@Override
public void run() {
//int num = 100;//100张票被三个线程共享使用
//死循环
while(true) {
//调用sellA方法
//sellA();
//调用sellB方法
sellB();
}
}
//定义同步方法sellB,不能指定锁对象
//使用this作为锁对象
public synchronized void sellB() {
//(1)判断是否有票
if (num > 0) {
//(2)有票: 打印输出一张票
//模拟出票的时间
try {Thread.sleep(100);}catch (Exception e){e.printStackTrace();}
String threadName = Thread.currentThread().getName();
System.out.println(threadName+"卖出第 "+num+" 张票...........");
//(3)票的数量减少1张
num--;
}
}
//定义普通方法sellA,内部使用同步代码块
public void sellA() {
//this代表调用sellA方法的对象,sellA方法是在run方法内部调用的,哪个对象调用run方法,该对象就是调用sellA方法的对象
//task对象调用run方法,sellA方法也是由task对象
synchronized (this) {
//(1)判断是否有票
if (num > 0) {
//(2)有票: 打印输出一张票
//模拟出票的时间
try {Thread.sleep(10);}catch (Exception e){e.printStackTrace();}
String threadName = Thread.currentThread().getName();
System.out.println(threadName+"卖出第 "+num+" 张票...........");
//(3)票的数量减少1张
num--;
}
}
}
}
//测试类
public class Demo03Tickets {
public static void main(String[] args) {
//3.创建Runnable接口的实现类的对象,线程任务对象
MySellTicketTask03 task = new MySellTicketTask03();
//4.创建3个线程对象,构造方法发传递线程任务对象
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
Thread t3 = new Thread(task);
//5.这3个线程对象分别调用start方法,开启线程
t1.start();
t2.start();
t3.start();
}
}
##死锁
两个线程(保证只能有2个)就会处于无限的等待中,即死锁。在程序中的死锁将出现在同步代码块的嵌套中。
若无外力作用,它们都将无法推进下去。
同步: 同步中嵌套同步
### 死锁对象的定义
/*
定义锁对象 保证只能有2个
*/
public class MyLock {
public static final MyLock LOCKA = new MyLock();
public static final MyLock LOCKB = new MyLock();
private MyLock(){}//外部无法创建对象
}
/*
定义线程任务类
*/
public class DeadLockTask implements Runnable{
//定义布尔变量,目的: 不同的线程执行不同的同步代码块
private boolean flag;
//构造方法
public DeadLockTask(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
while(true) {
if(flag) {
synchronized (MyLock.LOCKA) { System.out.println(Thread.currentThread().getName()+"if....lockA.....");
synchronized (MyLock.LOCKB) { System.out.println(Thread.currentThread().getName()+"if....lockB.....");
}
}
} else {
/*try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
synchronized (MyLock.LOCKB) { System.out.println(Thread.currentThread().getName()+"else....lockB.....");
synchronized (MyLock.LOCKA) { System.out.println(Thread.currentThread().getName()+"else....lockA.....");
}
}
}
}
}
}
//测试类
/*
死锁案例演示
死锁是指两个或两个以上的线程在执行过程中,由于竞争同步锁而产生的一种阻塞的现象,
若无外力作用,它们都将无法推进下去。
*/
public class Demo04DeadLock {
public static void main(String[] args) {
//创建线程任务对象
DeadLockTask taskA = new DeadLockTask(false);
DeadLockTask taskB = new DeadLockTask(true);
//创建线程对象,传递线程任务对象
Thread threadA = new Thread(taskA);
Thread threadB = new Thread(taskB);
//开启线程 调用start方法开启线程,指定线程名称
threadA.start();
threadB.start();
}
}