JavaDay6
多线程
单线程:一个程序能够使用一条执行路径,从开始到结束。
而多线程则为——一个进程有多条执行路径
多线程的创建
1、自己造一个类,继承Thread类,重写run()方法,创建该线程类的对象【线程对象】,启动start()
/*
1、自己造一个类,继承Thread类,重写run方法,创建该线程类的对象【线程对象】,启动【启动线程】。
*/
class MyThread1 extends Thread{
@Override
public void run() {
for(int i=1;i<=200;i++){
System.out.println(i);
}
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
MyThread1 t1 = new MyThread1(); //创建一个线程对象
MyThread1 t2 = new MyThread1(); //创建一个线程对象
MyThread1 t3 = new MyThread1(); //创建一个线程对象
// t1.run();
// t2.run();
// t3.run();
t1.start();
t2.start();
t3.start();
}
}
2、自己造一个类,实现Runnable接口,实现run()方法,创建该线程类对象【线程对象】,启动start()
/*
2、自己造一个类,实现Runnable接口,实现run方法,创建该线程类的对象,借助Thread类构造方法,创建一个线程对象,启动【启动线程】
*/
class MyRunnable1 implements Runnable{
@Override
public void run() {
for(int i=1;i<=200;i++){
//Thread.currentThread() -- 当前是哪一个线程在执行run方法的代码逻辑
System.out.println(Thread.currentThread().getName() + " - "+i);
}
}
}
public class MyRunnableDemo1 {
public static void main(String[] args) {
MyRunnable1 myRunnable1 = new MyRunnable1();
//Thread类构造方法
//Thread(Runnable target)
//分配一个新的 Thread对象。
// Thread t1 = new Thread(myRunnable1);
// Thread t2 = new Thread(myRunnable1);
// Thread t3 = new Thread(myRunnable1);
//Thread(Runnable target, String name) 传入Runnable对象的同时给线程起一个名字
//分配一个新的 Thread对象。
Thread t1 = new Thread(myRunnable1,"张成阳");
Thread t2 = new Thread(myRunnable1,"方直");
Thread t3 = new Thread(myRunnable1,"杨浩东");
t1.start();
t2.start();
t3.start();
}
}
/*
注意:
1、为什么要重写run方法?
一个线程要执行的功能,这个run方法就是每个线程对象启动时要执行的代码逻辑
2、启动线程千万不要直接调用run方法,因为这和普通的对象调用run方法没有任何区别。将来我们将一个线程对象启动后,由系统自动分配资源,创建线程,底层调用对应线程中的run方法代码逻辑
3、一个进程中多个线程执行之间,具有随机性,抢占式调度,线程启动的瞬间并不是立刻就执行,而是具备了CPU执行的资格将来当抢到CPU执行权的时候,才会执行。
4、线程对象调用start()方法的时候,才算启动,系统创建了一个线程对象,具备了CPU执行的资格,当抢到CPU执行权的时候
由该线程内部自动调用起对应的run方法代码逻辑,直到未来某一刻某个线程对象中的run方法代码逻辑执行完那么这个线程也就死亡了,变成垃圾,等待被回收。
*/
线程控制
休眠线程sleep()
中断线程stop()|interrupt()
中断后,后续代码继续运行
class MyThread2 extends Thread{
@Override
public void run() {
System.out.println(getName()+" 睡觉了....");
try {
Thread.sleep(10000); // 10s 阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+" 睡醒了....");
}
}
public class ThreadSleepDemo1 {
public static void main(String[] args) {
MyThread3 t1 = new MyThread3();
t1.setName("张成阳");
t1.start();
try {
Thread.sleep(5000);
// t1.stop(); // 终止t1线程的执行
t1.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
加入线程join()
使用join后,其它线程需等待join()线程执行完毕后再抢占执行。
class MyThread3 extends Thread{
public MyThread4() {
}
public MyThread4(String name) {
super(name);
}
@Override
public void run() {
for(int i=1;i<=200;i++){
System.out.println(getName()+" - "+i);
}
}
}
public class ThreadJoinDemo1 {
public static void main(String[] args) {
MyThread4 t1 = new MyThread4("张成阳");
MyThread4 t2 = new MyThread4("方直");
MyThread4 t3 = new MyThread4("杨浩东");
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
t3.start();
}
}
后台线程(守护线程)
/*
后台线程(守护线程):
用户线程
守护线程
一个程序如果只有守护线程的话,程序会停止。当用户线程没有了,守护线程就会没有。
*/
class MyThread4 extends Thread{
public MyThread6() {
}
public MyThread6(String name) {
super(name);
}
@Override
public void run() {
for(int i=1;i<=200;i++){
System.out.println(getName()+" - "+i);
}
}
}
public class ThreadDaemonDemo1 {
public static void main(String[] args) {
MyThread4 t1 = new MyThread4("刘备");
MyThread4 t2 = new MyThread4("张飞");
MyThread4 t3 = new MyThread4("关羽");
t2.setDaemon(true);
t3.setDaemon(true);
t1.start();
t2.start();
t3.start();
}
}
线程安全
如何判断一个程序是否有线程安全的问题:
a、是否有多线程?
b、是否有共享数据【变量】?
c、是否有多条语句操作共享数据?
那么我们知道了如何判断程序是否存在线程安全的问题,该如何解决?
1、synchronized关键字
2、lock锁
synchronized关键字
/*
synchronized关键字使用:
1、同步代码块,将操作共享数据的代码,使用同步代码块包起来,有点像上锁的概念
synchronized(全局唯一的对象[锁对象]){
//操作共享数据的代码
}
2、同步方法
synchronized(this[锁对象]){
//操作共享数据的代码
}
3、同步静态方法
synchronized(当前项目中的.class文件[锁对象]){
//操作共享数据的代码
}
*/
class MyRunnable4 implements Runnable{
int tickets = 100;
Object obj = new Object();
@Override
public void run() {
while (true){
synchronized (obj){
if(tickets>0){ // tickets=1
try {
// w1, w2, w3
Thread.sleep(20); // 阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 正在出售第 "+(tickets--)+" 张票。。");
}
}
}
}
}
public class SellTicketDemo4 {
public static void main(String[] args) {
MyRunnable4 myRunnable4 = new MyRunnable4();
Thread w1 = new Thread(myRunnable4, "窗口1");
Thread w2 = new Thread(myRunnable4, "窗口2");
Thread w3 = new Thread(myRunnable4, "窗口3");
w1.start();
w2.start();
w3.start();
}
}
lock锁
/*
Lock锁的使用
普通锁:ReentrantLock
只读锁:ReentrantReadWriteLock.ReadLock
只写锁:ReentrantReadWriteLock.WriteLock
*/
class MyRunnable6 implements Runnable {
int tickets = 100;
Object obj = new Object();
ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
// 加锁
lock.lock();
if (tickets > 0) { // tickets=1
try {
// w1, w2, w3
Thread.sleep(20); // 阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票。。");
}
// 释放锁
lock.unlock();
}
}
}
public class SellTicketDemo6 {
public static void main(String[] args) {
MyRunnable6 myRunnable6 = new MyRunnable6();
Thread w1 = new Thread(myRunnable6, "窗口1");
Thread w2 = new Thread(myRunnable6, "窗口2");
Thread w3 = new Thread(myRunnable6, "窗口3");
w1.start();
w2.start();
w3.start();
}
}
死锁:即线程之间存在相互等待的现象
等待唤醒机制
该机制建立在线程安全之上
等待唤醒机制中有两个重要角色:【生产者】、【消费者】
【生产者】:生产者在生产数据前需要判断之前生产的数据是否有剩余
【消费者】:消费数据前先查看是否有可供消费的数据,若有则继续消费,若无则通知生产者生产。
//生产者
public class ProductThread extends Thread{
Student student;
public ProductThread(Student student) {
this.student = student;
}
@Override
public void run() {
int i = 0;
// Student student = new Student();
while (true){
synchronized (student){
/*
对于生产者,在生产数据之前,先看一看数据有没有被消费
如果还没有被消费,那么就等待,通知消费者来消费数据
*/
if(student.isFlag()){
//等待,锁对象调用方法进行等待
try {
student.wait(); // 阻塞,当锁对象调用唤醒的方法的时候,继续往下运行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(i%2==0){
student.setName("查镕贤");
student.setAge(18);
}else {
student.setName("查镕贤2");
student.setAge(20);
}
i++;
student.setFlag(true);
student.notify(); // 通知消费者消费
}
}
}
}
//消费者
public class ConsumerThread extends Thread{
Student student;
public ConsumerThread(Student student) {
this.student = student;
}
@Override
public void run() {
// Student student = new Student();
while (true){
synchronized (student){
/*
对于消费者而言,消费数据之前,先看一看数据有没有产生,如果没有产生或上一次产生的数据已经被消费过
*/
if(!student.isFlag()){
try {
student.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(student.getName()+" - "+student.getAge());
student.setFlag(false);
student.notify();
}
}
}
}
//程序运行
public class ThreadDemo3 {
public static void main(String[] args) {
Student student = new Student();
//创建生产者线程对象
ProductThread productThread = new ProductThread(student);
//创建消费者线程对象
ConsumerThread consumerThread = new ConsumerThread(student);
productThread.start();
consumerThread.start();
}
}
线程组
ThreadGroup,建立线程组对线程进行管理。Java程序允许对线程组直接管理。
每个线程默认有一个线程组
/*
ThreadGroup: java提供用于描述线程组的类
1、每个线程默认有一个线程组 getThreadGroup(), 默认线程组的名字叫做main
2、为了方便对批量的线程做设置
*/
class MyThread1 extends Thread {
public MyThread1() {
}
public MyThread1(ThreadGroup group, String name) {
super(group, name);
}
@Override
public void run() {
for (int i = 1; i <= 200; i++) {
System.out.println(getName() + " - " + i);
}
}
}
public class ThreadGroupDemo1 {
public static void main(String[] args) {
//创建3个线程对象
// MyThread1 t1 = new MyThread1();
// MyThread1 t2 = new MyThread1();
// MyThread1 t3 = new MyThread1();
// System.out.println(t1.getThreadGroup().getName());
// System.out.println(t2.getThreadGroup().getName());
// System.out.println(t3.getThreadGroup().getName());
//需求:创建一个名字叫帅哥组的线程组,再创建几个线程对象放到线程组中
//ThreadGroup(String name) 构造一个新的线程组。
ThreadGroup tg1 = new ThreadGroup("帅哥组");
ThreadGroup tg2 = new ThreadGroup("修仙组");
//Thread(ThreadGroup group, String name) 分配一个新的 Thread对象。
//创建线程对象的时候,给线程设置一个线程组
MyThread1 t1 = new MyThread1(tg1,"查镕贤");
System.out.println("t1当前的线程名字叫做:"+t1.getName()+", 属于线程组:"+t1.getThreadGroup().getName());
MyThread1 t2 = new MyThread1(tg1,"查镕贤2");
System.out.println("t2当前的线程名字叫做:"+t2.getName()+", 属于线程组:"+t2.getThreadGroup().getName());
MyThread1 t3 = new MyThread1(tg1,"查镕贤3");
System.out.println("t3当前的线程名字叫做:"+t3.getName()+", 属于线程组:"+t3.getThreadGroup().getName());
//Thread(ThreadGroup group, String name) 分配一个新的 Thread对象。
//创建线程对象的时候,给线程设置一个线程组
MyThread1 t4 = new MyThread1(tg2,"查镕贤4");
System.out.println("t4当前的线程名字叫做:"+t4.getName()+", 属于线程组:"+t4.getThreadGroup().getName());
MyThread1 t5 = new MyThread1(tg2,"查镕贤5");
System.out.println("t5当前的线程名字叫做:"+t5.getName()+", 属于线程组:"+t5.getThreadGroup().getName());
MyThread1 t6 = new MyThread1(tg2,"查镕贤6");
System.out.println("t6当前的线程名字叫做:"+t6.getName()+", 属于线程组:"+t6.getThreadGroup().getName());
// 将修仙组的线程设置为守护线程
// t4.setDaemon(true);
// t5.setDaemon(true);
// t6.setDaemon(true);
tg2.setDaemon(true);
}
}
线程池
加快用户的访问速度,提高固定时间内的访问量
线程池需要手动关闭:.shutdown
创建线程除了刚开始说的两种方式外,接下来引入第三种:
实现Callable接口,借助线程池中的submit方法提交,启动。
class MyCallable implements Callable{
@Override
public Object call() throws Exception {
for (int i=1;i<=200;i++){
System.out.println(Thread.currentThread().getName()+" - "+i);
}
return null;
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i=1;i<=200;i++){
System.out.println(Thread.currentThread().getName()+" - "+i);
}
}
}
public class ThreadPoolDemo1 {
public static void main(String[] args) {
//创建一个固定大小的线程池
ExecutorService pool = Executors.newFixedThreadPool(2);
//将线程放入到线程池中运行
//Future<?> submit(Runnable task) 提交一个可运行的任务执行,并返回一个表示该任务的未来。
pool.submit(new MyRunnable()); //底层是使用一个Thread类将其封装成线程对象,启动 // pool-1-thread-1
pool.submit(new MyRunnable()); //底层是使用一个Thread类将其封装成线程对象,启动 // pool-1-thread-2
pool.submit(new MyRunnable()); //底层是使用一个Thread类将其封装成线程对象,启动
//<T> Future<T> submit(Callable<T> task) 提交值返回任务以执行,并返回代表任务待处理结果的Future。
pool.submit(new MyCallable());
pool.submit(new MyCallable());
pool.submit(new MyCallable());
//使用匿名内部类,来提交线程到线程池,不同的线程内部可以是不同的实现。
pool.submit(new Runnable() {
@Override
public void run() {
// 运行代码逻辑1
}
});
pool.submit(new Runnable() {
@Override
public void run() {
// 运行代码逻辑2
}
});
//线程池需要手动关闭
pool.shutdown();
}
}
注意:
Runnable接口和Callable接口的区别:
其中实现Runnable接口和实现Callable接口区别在于,Runnable接口中是实现run方法,run方法没有返回值而Callable接口中是实现call方法,call方法可以有返回值的,将来如果一个线程执行完毕后需要返回结果,那么就使用Callable接口借助线程池的方式实现多线程。
同时,还可使用匿名内部类来提交不同的线程到线程池
定时器
Timer:定时器
TimerTask:定时任务
关系:创建定时任务【TimerTask】由定时器【Timer】进行调度。
/*
Timer中提供了两种调度方式:
public void schedule(TimerTask task, long delay) 延迟指定时间后执行
public void schedule(TimerTask task,long delay,long period) 延迟指定时间后执行,之后每间隔固定时间重复执行
*/
public class TimerDemo {
public static void main(String[] args) {
//创建定时器
//Timer()
//创建一个新的计时器。
Timer timer = new Timer();
//public void schedule(TimerTask task, long delay)
timer.schedule(new MyTask(timer), 10000L);
//public void schedule(TimerTask task,long delay,long period) 延迟指定时间后执行,之后每间隔固定时间重复执行
timer.schedule(new MyTask2(), 10000L, 2000L);
}
}
//创建一个定时任务类,继承TimerTask抽象类,重写run方法,编写任务代码逻辑
class MyTask2 extends TimerTask{
Timer timer;
public MyTask2() {
}
public MyTask2(Timer timer) {
this.timer = timer;
}
@Override
public void run() {
for(int i=1;i<=3;i++){
Thread.sleep();
}
System.out.println("砰!!!爆炸了!!!");
fun1();
// 关闭定时器
timer.cancel();
}
public void fun1(){
}
}
//创建一个定时任务类,继承TimerTask抽象类,重写run方法,编写任务代码逻辑
class MyTask extends TimerTask{
Timer timer;
public MyTask(Timer timer) {
this.timer = timer;
}
@Override
public void run() {
System.out.println("砰!!!爆炸了!!!");
// fun1();
// 关闭定时器
timer.cancel();
}
设计模式
历代程序员开发时提供的经验和开发思路
设计模式分类:
创建型模式【重点】
行为型模式
结构型模式
创建型模式
简单工厂模式
a、好处是可通过一个类创建多种对象,不需要在测试类中new
b、不便之处是若对象种类太多,则需要频繁修改类
//自建的Animal类:
public abstract class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public abstract void eat();
public abstract void sleep();
}
//继承自上Animal类创建猫和老虎:
public class Cat extends Animal{
public Cat() {
}
public Cat(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("
标签:JavaDay6,Thread,void,线程,student,new,public
From: https://www.cnblogs.com/Roxan-bd/p/18675704