多线程相关,线程池,定时器

进程线程概念分析参考博客:https://blog.csdn.net/l1585931143/article/details/60610576

一个程序至少一个进程,一个进程至少一个线程。线程依托进程存在。

并行:时间段上来说多个程序运行

并发:时间点上来说程序运行,多个cpu实现程序的并发

 

 

jvm虚拟机启动是单线程还是多线程?        多线程

每个线程都有优先级

创建线程的方法有两种

1️⃣将类声明为Thread的子类,该子类重写Thread类的run方法,

线程中start和run的区别

start是使线程开始执行,java虚拟机调用该线程的run方法

run是对象调用方法,还是主线程在进行操作

public class ThreadDemo {

	public static void main(String[] args) {
			MyThread thread = new MyThread();
//			thread.run();
			thread.start();
			System.out.println("over");
	}

}
class MyThread extends Thread{
	public void run(){
		try {
			sleep(500);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		for (int i = 0; i < 10; i++) {
			System.out.println(i);
		}
	}
}

创建新线程并沉睡500ms,此时后面的system.out已经执行了(正经的start才会出现这种情况)

 

线程不能多次启动,会出现报错

Exception in thread "main" java.lang.IllegalThreadStateException

 

 

getName()          默认thread-0  获取线程名字

setName(String name) 设置线程名字

 

获取主线程对象

Thread thread2 = Thread.currentThread();
			System.out.println(thread2.getName());

 

 

 

线程的阻塞方法的使用

join方法:等待线程运行完之后再运行。括号中还可以加时间,超过最大等待时间就开始运行

public class TestJoin {
 
  public static void main(String[] args) {
   
    MyThread2 t1 = new MyThread2("TestJoin");
    t1.start();
    try {
      t1.join();  //join()合并线程,子线程运行完之后,主线程才开始执行
     }catch (InterruptedException e) {  }
      
     for(int i=0 ; i <10; i++)
              System.out.println("I am Main Thread");
   }
 }
 
 class MyThread2 extends Thread {
  
    MyThread2(String s) {
     super(s);
     }
     
  public void run() {
    for(int i = 1; i <= 10; i++) {
     System.out.println("I am "+getName());
     try {
      sleep(1000); //暂停,每一秒输出一次
      }catch (InterruptedException e) {
      return;
     }
     }
   }
  }

 


输出结果

 

I am TestJoin
I am TestJoin
I am TestJoin
I am TestJoin
I am TestJoin
I am TestJoin
I am TestJoin
I am TestJoin
I am TestJoin
I am TestJoin
I am Main Thread
I am Main Thread
I am Main Thread
I am Main Thread
I am Main Thread
I am Main Thread
I am Main Thread
I am Main Thread
I am Main Thread
I am Main Thread

 

 

 

yield()方法:暂停当前正在执行的线程对象,并执行其他线程

 

stop()方法已经过时

现在停止线程所用方法是使用标签

public class ThreadDemo3 {

	public static void main(String[] args) {
		Thread3 t = new Thread3();
		t.start();
		t.run();
	}

}
class Thread3 extends Thread{
	private boolean flag;
	
	public boolean isFlag() {
		return flag;
	}

	public void setFlag(boolean flag) {
		this.flag = flag;
	}

	@Override
	public void run() {
		for (int i = 0; i < 1000; i++) {
			if(i==3){
				flag=false;
			}
			if(!flag){
				return;
			}
			System.out.println(i);
		}
	}
}

符合停止条件时改变flag的值来实现让线程停止。

 

线程中断方法

interrupt():打破阻塞状态,中断线程,还会返回interruptException错误

 

配合join()的线程中断方法

//线程中断方法,配合join()
public class ThreadDemo4 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 通过构造方法将主线程对象传递给子线程
		Thread4 t = new Thread4(Thread.currentThread());
		t.start();
		try {
			t.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// Thread.currentThread().interrupt();//放在这里无意义
		System.out.println("over");
	}

}

class Thread4 extends Thread {
	private Thread mainThread;

	public Thread4(Thread mainThread) {
		this.mainThread = mainThread;

	}

	@Override
	public void run() {
		// 让主线程阻塞之后,再执行
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		for (int i = 0; i < 10; i++) {
			// 当i3的时候,中断线程
			if (i == 3) {
				mainThread.interrupt();
			}
			System.out.println(i);
		}
	}
}

 

 

 

 

配合sleep()的线程中断方法

public class ThreadDemo5 {

	public static void main(String[] args) {
		Thread5 t = new Thread5();
		t.start();
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		t.interrupt();
		System.out.println("over");
	}

}

class Thread5 extends Thread {
	public void run() {
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		for (int i = 0; i < 10; i++) {
			System.out.println(i);
		}
	}
}

 

线程的生命周期

线程先start启动,因为没有cpu执行权,所以没有执行资格,抢到cpu执行权,调用线程的方法,此时run,stop会线程执行结束,sleep,join,wait会进入阻塞状态,等待cpu

 

2️⃣创建线程的另一种方式是声明实现Runnable()接口的类,该类实现run方法,然后可以分配该类的实例,在创建thread的时候作为一个参数来传递并启动。

多线程可以执行一个Runnable任务

public class ThreadDemo6 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MyRunnable task = new MyRunnable();
//		多个线程执行同一个Runnable任务
		new Thread(task).start();
		new Thread(task).start();
	}

}
class MyRunnable implements Runnable{
	private int count=10;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(count>0){
			System.out.println(count);
			count--;
		}
	}
	
}

有资源共享,就用Runable方法

 

 

多线程的线程安全问题及同步代码块,同步方法相关

出现线程安全问题的原因?

多线程环境下且存在共享数据,同时共享数据被多条语句引用

解决线程安全问题的方法?

让操作共享数据的代码在任意时间只能被同一个线程所操作

可以使用同步代码块实现:synchronized(锁对象){

存在线程安全的代码

 }

同步代码块的优缺点

优点:解决了线程安全问题

缺点:每次运行的时候都要检查锁对象是否被释放

同步方法:

在run方法前面修饰符加上synchronized,将整个方法的代码都锁起来

非静态同步方法的锁对象又是什么呢?this

静态方法的锁对象是:当前类的字节码文件对象

锁对象:锁对象可以是任意对象,多个线程必须使用的是同一把锁,也就是说必须使用同一个对象

锁对象什么时候会释放?

1.同步代码执行完毕

2.线程进入等待状态

3.线程停止

 

什么时候使用同步代码块,什么时候使用同步方法?

当方法里面只有一部分代码存在安全问题时候,使用同步代码块

当方法里面所有的代码都存在安全问题的时候切当前锁对象可以this时使用同步方法

 

 

 

 

实现Runnnable接口的创建线程可以使用同步代码块和同步方法

继承Thread类的创建线程只能使用同步代码块,不能使用同步方法

售票程序

public class ThreadTest {

	public static void main(String[] args) {
		/*
		 * 线程同步安全问题出现的根据: 多线程环境 多线程操作共享数据 操作数据的语句是多行
		 * 线程安全问题的解决方法:让操作共享数据的代码在同一时间只能被同一个线程所操作
		
		 */
		// 集成Thread方式
		// TicketThread t = new TicketThread("窗口1");
		// t.start();
		// TicketThread t2 = new TicketThread("窗口2");
		// t2.start();
		// TicketThread t3 = new TicketThread("窗口3");
		// t3.start();

		// 实现Runnable接口的方式
		TicketRunnable ticket = new TicketRunnable();
		new Thread(ticket, "窗口1").start();
		new Thread(ticket, "窗口2").start();
		new Thread(ticket, "窗口3").start();
	}

}

 

 

 

继承Thread类

public class TicketThread extends Thread {
	// 所有进程共享资源是票,必须加static
	private static int ticket = 100;

	public TicketThread(String name) {
		// TODO Auto-generated constructor stub
		super(name);
	}

	@Override
	public void run() {
		synchronized (Object.class) {
			while (ticket > 0) {
				System.out.println(getName() + "正在出售第" + ticket + "张票");
				ticket--;
			}
			
		}
	}

}

 

 

 

实现Runnable接口

public class TicketRunnable implements Runnable {
	private int ticket = 100;

	@Override
	public void run() {
		// TODO Auto-generated method stub
			while (ticket > 0) {
				System.out.println(Thread.currentThread().getName() + "正在出售第" + ticket + "张票");
				ticket--;
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

 

 

 

 

 

火车进站小程序

线程方法:

public final void wait() 使线程等待

public final void notify() 随机唤醒等待的其中一个线程

public final void notifyAll() 唤醒所有等待中的线程

public void interrupt() 可以中断等待的线程状态

 

!!!!上述方法必须在同步代码里面通过锁对象调用object.class.调用

为什么定义在object类中?

因为锁对象可以是任意对象,又因为wait,notify,notifyAll必须通过锁对象调用,即任意对象都可以调用这些方法,同时又因为任意对象都可以调用的方法应该定义在Object类中,所以定义在Object类中。

public class EnterTrainDemo {

	public static void main(String[] args) {
		EnterTrainRunnable passenger = new EnterTrainRunnable();
		new Thread(passenger,"乘客1").start();
		new Thread(passenger,"乘客2").start();
		new Thread(passenger,"乘客3").start();
		new Thread(passenger,"乘客4").start();
		//等到乘客都进站了,进站之后再唤醒乘客
		try {
			Thread.sleep(50);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		passenger.setOpen(123456);
		new Thread(passenger,"工作人员").start();
	}

}
class EnterTrainRunnable implements Runnable{
	private boolean isOpen;
	public void setOpen(int key){
		if(key==123456){
			isOpen=true;
		}
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		synchronized (Object.class) {
			if(isOpen){
				isOpen=false;
				System.out.println(getThreadName()+"进站了,5秒钟后放行乘客");
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
//				Object.class.notify();//随机唤醒一个乘客
				Object.class.notifyAll();
			}else{
				System.out.println(getThreadName()+"正在等待");
				try {
					Object.class.wait();//线程进入等待状态,锁对象会释放
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(getThreadName()+"被放行了");
			}
		}
	}
	private String getThreadName() {
		// TODO Auto-generated method stub
		return Thread.currentThread().getName();
	}
	
}

 

 

 

关于锁Lock

public class TicketRunnable implements Runnable {
	private int ticket = 100;
	private Lock lock=new ReentrantLock();
	@Override
	public void run() {
		// TODO Auto-generated method stub
		lock.lock();
			while (ticket > 0) {
				System.out.println(Thread.currentThread().getName() + "正在出售第" + ticket + "张票");
				ticket--;
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			lock.unlock();
		}
	}

 

 

 

尽量多个线程使用同一把锁,可以避免死锁。

 

 

 

线程池:为了防止频繁创建销毁线程浪费系统资源而创建的线程容器

全是静态成员方法,是个工具类。

从JDK1.5之后,java内置线程池

三种创建线程池的方法

1️⃣创建一个存活60s的线程池

ExecutorService threadPool = Executors.newCachedThreadPool();
		threadPool.execute(myRunnable);

 

 

 

2️⃣创建一个只放一个线程的线程池

ExecutorService threadPool = Executors.newSingleThreadExecutor();
		threadPool.execute(myRunnable);

 

3️⃣创建一个指定线程数的线程池

ExecutorService threadPool = Executors.newFixedThreadPool(3)
		threadPool.execute(myRunnable);

线程池的关闭

 

threadPool.shutdown()

 

 

自定义线程池工具类

public class ThreadPoolUtils {

	public static void execute(Runnable task) {
			private static ExecutorService threadPool = Executors.newCachedThreadPool();
			public static void execute(Runnable task){
				threadPool.execute(task);
			}
	}

}

 

 

 

匿名内部类创建线程的两种方式

public class ThreadDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new Thread(){
			@Override
			public void run() {
				for (int i = 0; i < 10; i++) {
					System.out.println(i);
				}
			}
		}.start();
	new Thread(new Runnable() {
		
		@Override
		public void run() {
			// TODO Auto-generated method stub
			
		}
	}).start();
}
}
class MyThread extends Thread{
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(i);
		}
	}
}
class MyRunnable implements Runnable{
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(i);
		}
	}
}

 

 

 

线程的定时器:可用于调度多个定时任务以后台线程的方式执行。可安排任务执行一次,或者定期重复执行

public class TimerDemo {

	public static void main(String[] args) {
//		创建一个新的定时器
		Timer timer = new Timer();
//		要被执行的任务
		MyTimerTask mytimerTask = new MyTimerTask();
//		安排在制定延迟后执行指定任务,多长时间之后任务开始执行,执行之后每隔多久开始执行下一个
		timer.schedule(mytimerTask, 1000,1000);
		timer.cancel();
	}

}
class MyTimerTask extends TimerTask{

	@Override
	public void run() {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println(format.format(new Date()));
//		当任务执行完毕之后,关闭定时器
	}
	
}

 

 

 

同步有三种方式

同步代码块:锁对象可以使任意对象,所以用object。

同步方法:锁对象是this,关键字放在方法的修饰符位置上

使用lock子类对象:创建ReentrantLock子类对象然后使用lock和unlock分别进行加锁和解锁。

run()和start()的区别

run()没有创建新的线程。start()创建了新的线程。

sleep()和wait()方法的区别?

sleep是睡眠指定时间,等指定时间到了就苏醒

wait:只能在同步代码中通过锁对象调用,必须通过锁对象唤醒。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值