22.01 多线程的实现方式1
A:多线程的实现方式1:
a:继承Thread类
b:步骤及代码演示
c:几个小问题:
启动线程使用的是哪个方法
线程能不能多次启动
run()和start()方法的区别
我们启动线程不是使用run方法,而应该是start方法,使该线程开始执行;
Java虚拟机调用该线程的 run 方法
为什么要重写run方法?
这个类是一个线程类,那么在这个类中我们能不能写一些其他方法呢?
可以写其他方法
其他方法中封装的代码都是需要被我们线程执行的吗?
不一定,也就是run方法中封装应该是必须被线程执行的代码
run方法中的代码的书写原则:一般是比较耗时的代码
public class MyTest {
public static void main ( String[ ] args) {
MyThread mt = new MyThread ( ) ;
mt. start ( ) ;
MyThread mt2 = new MyThread ( ) ;
mt2. start ( ) ;
}
}
public class MyThread extends Thread {
@Override
public void run ( ) {
for ( int i = 0 ; i < 100 ; i++ ) {
System. out. println ( i) ;
}
}
public void show ( ) {
System. out. println ( "show方法" ) ;
}
}
22.02 获取和设置线程对象名称
A:Thread类的基本获取和设置方法
public final String getName() //获取线程名称
public final void setName(String name) //设置线程名称
public static Thread currentThread() //获取当前执行的线程
其实通过构造方法也可以给线程起名字
public static void main ( String[ ] args) {
Thread thread = Thread. currentThread ( ) ;
thread. setName ( "主线程" ) ;
String name = thread. getName ( ) ;
System. out. println ( name) ;
MyThread mt = new MyThread ( ) ;
mt. setName ( "lcy" ) ;
mt. start ( ) ;
}
public class MyThread extends Thread {
@Override
public void run ( ) {
System. out. println ( this ) ;
for ( int i = 0 ; i < 100 ; i++ ) {
System. out. println ( this . getName ( ) + "==" + i) ;
}
}
}
22.03 线程调度及获取和设置线程优先级
A:如何设置和获取线程优先级
public final int getPriority() //获取线程的优先级
public final void setPriority(int newPriority) //设置线程的优
//先级
public final int getPriority() //返回线程的优先级
线程的默认优先级是5
给线程设置优先级:范围是1-10
public final void setPriority(int newPriority)
public class MyTest {
public static void main ( String[ ] args) {
MyThread mt1 = new MyThread ( ) ;
MyThread mt2 = new MyThread ( ) ;
mt1. setName ( "线程A" ) ;
mt2. setName ( "线程B" ) ;
mt1. setPriority ( Thread. MIN_PRIORITY) ;
mt2. setPriority ( Thread. MAX_PRIORITY) ;
int priority = mt1. getPriority ( ) ;
int priority1 = mt2. getPriority ( ) ;
System. out. println ( priority) ;
System. out. println ( priority1) ;
mt1. start ( ) ;
mt2. start ( ) ;
}
}
public class MyThread extends Thread {
@Override
public void run ( ) {
for ( int i = 0 ; i < 100 ; i++ ) {
System. out. println ( this . getName ( ) + "===" + i) ;
}
}
}
22.04 休眠线程
A:线程休眠:
public static void sleep(long millis) //线程休眠
public class MyTest {
public static void main ( String[ ] args) throws InterruptedException {
System. out. println ( "广告页面" ) ;
Thread. sleep ( 1000 * 60 ) ;
System. out. println ( "跳到主页面" ) ;
MyThread mt1 = new MyThread ( ) ;
mt1. setName ( "线程A" ) ;
mt1. start ( ) ;
}
}
public class MyThread extends Thread {
@Override
public void run ( ) {
try {
Thread. sleep ( 1000 * 3 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
for ( int i = 0 ; i < 100 ; i++ ) {
System. out. println ( this . getName ( ) + "===" + i) ;
}
}
}
22.05 加入线程
A:加入线程
public final void join()
等待该线程执行完毕了以后,其他线程才能在此执行
注意事项:在线程启动之后,在调用方法
public class MyTest {
public static void main ( String[ ] args) throws InterruptedException {
MyThread mt0 = new MyThread ( ) ;
MyThread mt1 = new MyThread ( ) ;
MyThread mt2 = new MyThread ( ) ;
mt0. setName ( "刘备" ) ;
mt1. setName ( "关羽" ) ;
mt2. setName ( "张飞" ) ;
mt0. start ( ) ;
mt0. join ( ) ;
mt1. start ( ) ;
mt1. join ( ) ;
mt2. start ( ) ;
mt2. join ( ) ;
}
}
public class MyThread extends Thread {
@Override
public void run ( ) {
for ( int i = 0 ; i < 100 ; i++ ) {
System. out. println ( this . getName ( ) + "===" + i) ;
}
}
}
22.06 礼让线程
A:礼让线程:
public static void yield() //暂停当前正在执行的线程对象,并执
//行其他线程
public class MyTest {
public static void main ( String[ ] args) throws InterruptedException {
MyThread mt1 = new MyThread ( ) ;
MyThread mt2 = new MyThread ( ) ;
mt1. setName ( "关羽" ) ;
mt2. setName ( "张飞" ) ;
mt1. start ( ) ;
mt2. start ( ) ;
}
}
public class MyThread extends Thread {
@Override
public void run ( ) {
for ( int i = 0 ; i < 1000 ; i++ ) {
Thread. yield ( ) ;
System. out. println ( this . getName ( ) + "===" + i) ;
}
}
}
22.07 守护线程
A:守护线程
public final void setDaemon(boolean on)
将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,
Java虚拟机退出。
该方法必须在启动线程前调用。
B:Java用户线程和守护线程
1.用户线程和守护线程的区别
用户线程和守护线程都是线程,区别是Java虚拟机在所有用户线程
dead后,程序就会结束。而不管是否还有守护线程还在运行,若守护
线程还在运行,则会马上结束。
2.用户线程和守护线程的适用场景
由两者的区别及dead时间点可知,守护线程不适合用于输入输出或计
算等操作,因为用户线程执行完毕,程序就dead了,适用于辅助用户
线程的场景,如JVM的垃圾回收,内存管理都是守护线程。
3.创建守护线程
调用线程对象的方法setDaemon(true),设置线程为守护线程
1)thread.setDaemon(true)必须在thread.start()之前设置
2)在Daemon线程中产生的新线程也是Daemon的
3)不是所有的应用都可以分配给Daemon线程来进行服务,比如
读写操作或者计算逻辑。因为Daemon Thread还没来得及进行
操作,虚拟机可能已经退出了。
public class MyTest {
public static void main ( String[ ] args) throws InterruptedException {
Thread. currentThread ( ) . setName ( "刘备" ) ;
MyThread mt1 = new MyThread ( ) ;
MyThread mt2 = new MyThread ( ) ;
mt1. setName ( "关羽" ) ;
mt2. setName ( "张飞" ) ;
mt1. setDaemon ( true ) ;
mt2. setDaemon ( true ) ;
mt1. start ( ) ;
mt2. start ( ) ;
for ( int i = 0 ; i < 100 ; i++ ) {
System. out. println ( "主线程" + i) ;
}
}
}
public class MyThread extends Thread {
@Override
public void run ( ) {
for ( int i = 0 ; i < 1000 ; i++ ) {
System. out. println ( this . getName ( ) + "===" + i) ;
}
}
}
22.08 中断线程
A:中断线程
public final void stop(); 停止线程的运行
public void interrupt(); 当线程调用wait(),sleep(long time)
方法的时候处于阻塞状态,可以通过这
个方法清除阻塞
public class MyTest {
public static void main ( String[ ] args) throws InterruptedException {
MyThread mt1 = new MyThread ( ) ;
mt1. setName ( "线程A" ) ;
mt1. start ( ) ;
Thread. sleep ( 100 ) ;
mt1. stop ( ) ;
}
}
public class MyThread extends Thread {
@Override
public void run ( ) {
for ( int i = 0 ; i < 100000 ; i++ ) {
System. out. println ( this . getName ( ) + "===" + i) ;
}
}
}
public class MyTest {
public static void main ( String[ ] args) throws InterruptedException {
MyThread mt1 = new MyThread ( ) ;
mt1. setName ( "线程A" ) ;
mt1. start ( ) ;
Thread. sleep ( 2000 ) ;
mt1. interrupt ( ) ;
}
}
public class MyThread extends Thread {
@Override
public void run ( ) {
try {
Thread. sleep ( 1000 * 10 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
for ( int i = 0 ; i < 100 ; i++ ) {
System. out. println ( this . getName ( ) + "===" + i) ;
}
}
}
22.09 多线程的实现方式2
A:实现Runnable接口
这种方式拓展性强,实现一个接口,还可以再去继承其他类
public class MyTest {
public static void main ( String[ ] args) {
MyRunnable mr = new MyRunnable ( ) ;
Thread th = new Thread ( mr) ;
th. start ( ) ;
}
}
public class MyRunnable implements Runnable {
@Override
public void run ( ) {
for ( int i = 0 ; i < 100 ; i++ ) {
System. out. println ( i) ;
}
}
}
22.10 多线程的实现方式3
A:实现Callable接口。
相较于实现Runnable接口的方式,方法可以有返回值,并且可以抛出异常。
B:执行Callable方式,需要FutureTask实现类的支持,用于接收运算结果。
FutureTask是Future接口的实现类
C:实现步骤
1.创建一个类实现Callable接口
2.创建一个FutureTask类将Callable接口的子类对象作为参数传进去
3.创建Thread类,将FutureTask对象作为参数传进去
4.开启线程
public class MyTest {
public static void main ( String[ ] args) throws ExecutionException, InterruptedException {
MyCallable mc = new MyCallable ( ) ;
FutureTask< Object> oft = new FutureTask < > ( mc) ;
Thread th = new Thread ( oft) ;
th. setName ( "线程A" ) ;
th. start ( ) ;
Object o = oft. get ( ) ;
System. out. println ( o) ;
}
}
public class MyCallable implements Callable < Object> {
@Override
public Object call ( ) throws Exception {
for ( int i = 0 ; i < 100 ; i++ ) {
System. out. println ( Thread. currentThread ( ) . getName ( ) + "===" + i) ;
}
return 100 ;
}
}
22.11 线程安全问题的产生原因分析
A:判断一个多线程应用程序是否有问题的标准
a:是否是多线程环境
b:是否存在共享数据
c:是否存在多条语句同时操作共享数据
B:解决方法
需要使用同步代码块
格式:
synchronized(对象){ //不能在括号里直接new对象
要被同步的代码;
}
这个同步代码块保证数据的安全性的一个主要因素就是这个对象,这个对
象要定义为 静态成员变量 才能被所有线程共享
同步代码块的锁对象:任意一个对象
同步方法的锁对象:this
静态同步方法的锁对象:当前类对应的字节码文件对象
public static void main ( String[ ] args) {
CellRunnable cr = new CellRunnable ( ) ;
Thread th1 = new Thread ( cr, "窗口1" ) ;
Thread th2 = new Thread ( cr, "窗口2" ) ;
Thread th3 = new Thread ( cr, "窗口3" ) ;
th1. start ( ) ;
th2. start ( ) ;
th3. start ( ) ;
}
public class CellRunnable implements Runnable {
int piao = 100 ;
static Object obj = new Object ( ) ;
int i = 0 ;
@Override
public void run ( ) {
while ( true ) {
if ( i% 2 == 0 ) {
synchronized ( obj) {
if ( piao > 0 ) {
try {
Thread. sleep ( 50 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
System. out. println ( Thread. currentThread ( ) . getName ( ) + "正在售卖第" + piao-- + "张票" ) ;
}
}
} else {
maiPiao ( ) ;
}
i++ ;
}
}
public synchronized void maiPiao ( ) {
System. out. println ( this . getClass ( ) . getName ( ) ) ;
if ( piao > 0 ) {
try {
Thread. sleep ( 50 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
System. out. println ( Thread. currentThread ( ) . getName ( ) + "正在售卖第" + piao-- + "张票" ) ;
}
}
}
public static void main ( String[ ] args) {
CellRunnable cr = new CellRunnable ( ) ;
Thread th1 = new Thread ( cr, "窗口1" ) ;
Thread th2 = new Thread ( cr, "窗口2" ) ;
Thread th3 = new Thread ( cr, "窗口3" ) ;
th1. start ( ) ;
th2. start ( ) ;
th3. start ( ) ;
}
public class CellRunnable implements Runnable {
static int piao = 100 ;
static Object obj = new Object ( ) ;
int i = 0 ;
@Override
public void run ( ) {
while ( true ) {
if ( i% 2 == 0 ) {
synchronized ( CellRunnable. class ) {
if ( piao > 0 ) {
try {
Thread. sleep ( 50 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
System. out. println ( Thread. currentThread ( ) . getName ( ) + "正在售卖第" + piao-- + "张票" ) ;
}
}
} else {
maiPiao ( ) ;
}
i++ ;
}
}
public static synchronized void maiPiao ( ) {
if ( piao > 0 ) {
try {
Thread. sleep ( 50 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
System. out. println ( Thread. currentThread ( ) . getName ( ) + "正在售卖第" + piao-- + "张票" ) ;
}
}
}
public static void main ( String[ ] args) {
CellRunnable cr = new CellRunnable ( ) ;
Thread th1 = new Thread ( cr, "窗口1" ) ;
Thread th2 = new Thread ( cr, "窗口2" ) ;
Thread th3 = new Thread ( cr, "窗口3" ) ;
th1. start ( ) ;
th2. start ( ) ;
th3. start ( ) ;
}
public class CellRunnable implements Runnable {
int piao = 100 ;
static Object obj = new Object ( ) ;
@Override
public void run ( ) {
while ( true ) {
maiPiao ( ) ;
}
}
public synchronized void maiPiao ( ) {
if ( piao > 0 ) {
try {
Thread. sleep ( 50 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
System. out. println ( Thread. currentThread ( ) . getName ( ) + "正在售卖第" + piao-- + "张票" ) ;
}
}
}
22.12 Lock锁
A:Lock和ReentrantLock
void lock() 加锁
void unlock() 释放锁
最典型的代码:
class X {
private final ReentrantLock lock = new ReentrantLock();
//...
public void m() {
lock.lock(); //block until condition holds
try {
//... method body
} finally {
lock.unlock();
}
}
}
public class Demo02Ticket {
public static void main ( String[ ] args) {
CellRunnable cr = new CellRunnable ( ) ;
Thread th1 = new Thread ( cr, "窗口1" ) ;
Thread th2 = new Thread ( cr, "窗口2" ) ;
Thread th3 = new Thread ( cr, "窗口3" ) ;
th1. start ( ) ;
th2. start ( ) ;
th3. start ( ) ;
}
}
public class CellRunnable implements Runnable {
static int piao = 100 ;
static Lock lock = new ReentrantLock ( ) ;
@Override
public void run ( ) {
while ( true ) {
lock. lock ( ) ;
try {
if ( piao > 0 ) {
try {
Thread. sleep ( 50 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
System. out. println ( Thread. currentThread ( ) . getName ( ) + "正在售卖第" + piao-- + "张票" ) ;
}
} catch ( Exception e) {
e. printStackTrace ( ) ;
} finally {
lock. unlock ( ) ;
}
}
}
}
B:死锁问题
如果出现同步嵌套,就容易产生死锁问题
指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种
互相等待现象
public static void main ( String[ ] args) {
MyThread th1 = new MyThread ( true ) ;
MyThread th2 = new MyThread ( false ) ;
th1. start ( ) ;
th2. start ( ) ;
}
public interface LockUtils {
public static final Object objA = new Object ( ) ;
public static final Object objB = new Object ( ) ;
}
public class MyThread extends Thread {
private boolean flag;
public MyThread ( boolean flag) {
this . flag = flag;
}
@Override
public void run ( ) {
if ( flag) {
synchronized ( LockUtils. objA) {
System. out. println ( "true线程,持有了objA锁,进来了" ) ;
synchronized ( LockUtils. objB) {
System. out. println ( "true线程,持有了objB锁,进来了" ) ;
}
}
} else {
synchronized ( LockUtils. objB) {
System. out. println ( "false线程,持有了objB锁,进来了" ) ;
synchronized ( LockUtils. objA) {
System. out. println ( "false线程,持有了objA 锁,进来了" ) ;
}
}
}
}
}