文章目录
今日重点:
1.掌握线程的两种创建方式及其区别
2.掌握解决线程安全的同步代码块及同步方法
3.掌握线程的常用方法
4.理解线程的生命周期
5.理解线程安全问题的产生原因及其解决方法
一,复习
1.程序,进程与线程的区别
程序:是为完成特定任务,用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象
进程:是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生,存在和消亡的过程
———————生命周期
线程:进程可进一步细化为线程,是一个程序内部的一条执行路径。
若一个进程同一时间并行执行多个线程,就是支持多线程的。
线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器,线程切换的开销小
一个进程中多个线程共享相同的内存单元,但是同时也会带来一定的安全隐患。
2.并行与并发的区别
并行:多个CPU执行多个任务;比如:多个人同时做不同的事。
并发:一个CPU(采用时间片)同时执行多个任务。比如:秒杀,多个人做同一件事。
并发看似多个任务同时进行,其实是多个任务在短暂的时间片内进行切换
并行是真正意义上的一同执行。
并行与并发的区别:
①并行是指多个事件在同一时刻发生,而并发是指多个事务在某一个时间间隔内发生。
②并行是不同实体上的多个事件,并发是同一实体上的不同事件
③并行是在多台处理器上处理多个任务,并发是在一台处理器上处理多件事情
二,线程的创建(两种传统的方式)
1.方式一:继承Thread类
步骤:
1.创建Thread类的子类
2.重写Thread类中的run()方法;将当前线程要执行的操作声明在run()内
3.实例化Thread的子类
4.通过Thread类的子类对象调用其start():①启动线程②调用当前线程的run()
说明
①如果通过Thread类的子类对象调用run()方法,则不能够实现多线程操作,只能算是一次方法的重写,多线程的启动必须调用start()方法
②每个对象的start()只能调用一次,多次调用会报IllegalThreadStateException
练习:
public class ThreadTest {
public static void main(String[] args) {
// EvenNumber evenNumber = new EvenNumber();
// evenNumber.start();
OddNumber oddNumber = new OddNumber();
oddNumber.start();
}
}
class OddNumber extends Thread{//奇数
public void run() {
for(int i = 0;i <= 100;i++) {
if(i%2!=0) {
System.out.println(Thread.currentThread().getName()+"**"+i);
}
}
}
}
2.方式二:实现Runnable接口
步骤:
1.创建实现Runnable接口的子类,重写run()方法。
2.创建实现Runnable接口的子类对象
3.创建Thread类的实例对象,并将Runnable接口的子类对象放在其构造方法中
4.通过Thread类的实例对象调用start()
练习
public class ThreadTest2 {
public static void main(String[] args) {
windows1 w = new windows1();
Thread t1 = new Thread(w, "窗口1");
Thread t2 = new Thread(w, "窗口2");
Thread t3 = new Thread(w, "窗口3");
t1.start();
t2.start();
t3.start();
new Thread(new Runnable() {
@Override
public void run() {
for(int i = 1;i <= 100;i++) {
if(i%2!=0) {
System.out.println(Thread.currentThread().getName()+"**"+i);
}
if(i%20==0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
},"打印奇数!!").start();
}
}
class windows1 implements Runnable {
private int ticket = 1000;
@Override
public void run() {
while (true) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "票号为:"
+ ticket);
ticket--;
if(ticket==200) {
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} else {
break;
}
}
}
}
3.两种方式的对比
* 相同点:都需要进行方法的重写(run());启动线程都需要调用Thread类的start()
* 对比:① 类可以实现多个接口;但是只能继承一个父类 ② 实现的方式更方便的来处理有共享数据的情况
* 结论:实现Runnable的方式要好于继承Thread的方式
* 联系:public class Thread implements Runnable
三,线程常用的方法
start()
run()
currentThread()
getName()
setName()
sleep(long milisecond)://一旦执行该方法,线程阻塞milisecond毫秒次
yield():每当执行此方法时,线程主动释放cpu执行权。
join():在线程A中调用线程B的方法,线程A进入阻塞状态,直到线程B执行完成后,线程A不再是阻塞状态,开始正常执行。
isAlive():判断当前线程是否存活
线程优先级
①优先级的等级:
MIN_PRIORITY = 1
NORM_PRIORITY = 5 默认优先级
MAX_PRIORITY = 10
②如何设置优先级
getPriority():
setPriority(int priority)://设置
③调度策略
高优先级要抢占低优先级的策略
高优先级的策略只是从概率上面来讲,并不是一定能够抢占成功
四,线程的生命周期
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N6W9KPn8-1584062778899)(C:\Users\xxxxxx\AppData\Roaming\Typora\typora-user-images\1583840248496.png)]
五,线程的同步
1.同步机制,用于解决线程安全问题
* 例题:开启三个窗口售票,总票数为100张。使用Runnable接口实现类的方式实现
*
* 1. 出现的问题:出现了重票和错票 ---> 即为线程安全问题
* 2. 出现的原因:由于一个线程在操作ticket尚未操作完的情况下,其他线程参与进来继续操作ticket,导致出现了重票和错票。
* 3. 如何解决? 必须保证一个线程操作ticket,在完成操作完的时候,其他线程才能参与进行继续操作ticket.
*
* 4. Java是如何实现的?使用同步机制,解决线程的安全问题
2.方式一:同步代码块
方式一:
synchronized(同步监视器){
//需要被同步的代码
}
说明:①需要被同步的代码,即为共享数据的代码,要求:包裹共享数据的代码,不能包多了,也不能包少了
②何为共享数据?多个线程共同操作的数据。比如ticket
③同步监视器:俗称锁,可以为任意类型的一个类的对象。
要求:多个线程,必须共用同一个监视器
④同步监视器可以考虑用this,也可以用当前类.class
同步代码块解决实现Runnable接口多线程不同步问题
public class SynchronizedTest {
public static void main(String[] args) {
windows w = new windows();
Thread t1 = new Thread(w, "窗口1");
Thread t2 = new Thread(w, "窗口2");
Thread t3 = new Thread(w, "窗口3");
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(111);
}
}).start();
t1.start();
t2.start();
t3.start();
}
}
class windows implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true) {
synchronized (this) {
if (ticket > 0) {
// try {
// Thread.sleep(30);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
System.out.println(Thread.currentThread().getName()
+ "票号为:" + ticket);
ticket--;
} else {
break;
}
}
}
}
}
同步代码块解决继承Thread类的问题
public class SynchrnoizedThreadTest {
public static void main(String[] args) {
desk d1 = new desk();
desk d2 = new desk();
desk d3 = new desk();
d1.start();
d2.start();
d3.start();
}
}
class desk extends Thread {
private static int ticket = 100;
@Override
public void run() {
while (true) {
synchronized (desk.class) {
if (ticket > 0) {
// try {
// Thread.sleep(30);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
System.out.println(Thread.currentThread().getName()
+ "票号为:" + ticket);
ticket--;
} else {
break;
}
}
}
}
}
3.方式二:同步方法
使用同步方法解决通过实现Runnable完成多线程中遇到的线程不同步问题
public class SynchrnoizedMethoedTest {
public static void main(String[] args) {
move m1 = new move();
Thread t1 = new Thread(m1);
Thread t2 = new Thread(m1);
Thread t3 = new Thread(m1);
t1.start();
t2.start();
t3.start();
}
}
class move implements Runnable {
private int ticket = 100;
@Override
public void run() {
// TODO Auto-generated method stub
for (; ticket > 0;) {
show();
}
}
private synchronized void show() {
if (ticket > 0) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "票号为:"
+ ticket);
ticket--;
}
}
}
使用同步方法解决通过继承Thread类完成多线程中遇到的线程不同步问题
public class SynchrnoizedMethoedTest2 {
public static void main(String[] args) {
desk1 d1 = new desk1();
desk1 d2 = new desk1();
desk1 d3 = new desk1();
d1.start();
d2.start();
d3.start();
}
}
class desk1 extends Thread {
private static int ticket = 100;
@Override
public void run() {
for (; ticket > 0;) {
show();
}
}
private static synchronized void show() {
if (ticket > 0) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "票号为:" + ticket);
ticket--;
}
}
}
();
desk1 d3 = new desk1();
d1.start();
d2.start();
d3.start();
}
}
class desk1 extends Thread {
private static int ticket = 100;
@Override
public void run() {
for (; ticket > 0;) {
show();
}
}
private static synchronized void show() {
if (ticket > 0) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "票号为:" + ticket);
ticket--;
}
}
}