多线程
线程是依赖于进程存在的
进程就是正在运行的程序,是系统进行资源分配和调用的独立单位。
每一个进程都有它自己的内存空间和系统资源。
一个进程可以启动多个线程
比如java程序:
JVM就是一个进程,main为主线程,垃圾回收也是一个线程,两个线程并发
线程:在一个进程内部又可以执行多个任务,而这每一个任务我们就可以看成是一个线程。是程序使用CPU的基本单位。所以,进程是拥有资源的基本单位, 线程是CPU调度的基本单位。
多线程的作用不是提高执行速度,而是为了提高应用程序的使用率
程序在运行的使用,都是在抢CPU的时间片(执行权),如果是多线程的程序,那么在抢到
CPU的执行权的概率应该比较单线程程序抢到的概率要大,CPU在多线程程序中执行的时间要比单线程多,所以就提高了程序的使用率.但是即使是多线程程序,那么他们中的哪个线程能抢占到CPU的资源呢,这个是不确定的,所以多线程具有随机性.
并发:
指应用能够交替执行不同的任务
并行:
指应用能够同时执行不同的任务
进程并行,线程并发
实现多线程
方式一:
创建一个类继承Thread类
重写Thread类的run方法
new出创建类,调用start方法开启线程
方式二:(扩展性强,实现接口,可以去继承其他类)
创建一个类去实现Runnable接口
重写Runnable接口的run方法
分配创建类的实例
再创建Thread对象,将实例传入Thread对象
调用start方法开启线程
方式三:(这种方式有返回值,可以抛出异常)
创建一个类实现 Callable 接口
重写Callable接口中的call方法
创建一个FutureTask类将Callable接口的子类对象作为参数传进去
创建Thread类, 将FutureTask对象作为参数传进去
调用start方法开启线程
举例
package org. javase. 线程;
public class Test2 {
public static void main ( String[ ] args) {
MyThread1 myThread = new MyThread1 ( ) ;
myThread. start ( ) ;
}
}
class MyThread1 extends Thread {
@Override
public void run ( ) {
}
}
package org. javase. 线程;
public class Test2 {
public static void main ( String[ ] args) {
MyThread1 myThread = new MyThread1 ( ) ;
Thread thread = new Thread ( myThread) ;
thread. start ( ) ;
}
}
class MyThread1 implements Runnable {
@Override
public void run ( ) {
}
}
package org. javase. 线程;
import java. util. concurrent. Callable;
import java. util. concurrent. FutureTask;
public class Test2 {
public static void main ( String[ ] args) {
MyCallable mc = new MyCallable ( 100 ) ;
FutureTask< Integer> ft = new FutureTask < Integer> ( mc) ;
Thread thread = new Thread ( ft) ;
thread. start ( ) ;
}
}
class MyCallable implements Callable < Integer> {
private int num;
public MyCallable ( int num) {
this . num = num;
}
@Override
public Integer call ( ) throws Exception {
int sum = 0 ;
for ( int i = 0 ; i < num ; i++ ) {
sum += i;
}
return sum;
}
}
为什么要重写run方法?
这个类是一个线程类,那么在这个类中我们可不可以写一些其他的方法呢?
我们可以在写其他的方法,那么其他方法中封装的代码都是需要被我们线程执行的吗? 不一定
那么也就是run方法中封装应该是必须被线程执行的代码.
run方法中的代码的书写原则: 一般是比较耗时的代码
Thread类的方法
public final String getName()获取线程名称
public final void setName(String name)设置线程名称
public static Thread currentThread()获取当前执行的线程
public final int getPriority() //获取线程的优先级
public final void setPriority(int newPriority)//设置线程的优先级
public final int getPriority()返回线程的优先级,(线程的默认优先级是5)
线程休眠
package org. westos. 作业;
public class ThreadTest1 {
public static void main ( String[ ] args) throws InterruptedException {
System. out. println ( "主线程开始执行了" ) ;
Thread. sleep ( 2000 ) ;
System. out. println ( "主线程下面的代码" ) ;
MyThread1 th1 = new MyThread1 ( "A线程" ) ;
MyThread1 th2 = new MyThread1 ( "B线程" ) ;
th1. start ( ) ;
th2. start ( ) ;
}
}
class MyThread1 extends Thread {
public MyThread1 ( String name) {
super ( name) ;
}
@Override
public void run ( ) {
for ( int i = 0 ; i < 100 ; i++ ) {
try {
Thread. sleep ( 1000 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
String name1 = Thread. currentThread ( ) . getName ( ) ;
System. out. println ( name1 + "===" + i) ;
}
}
}
加入线程
package org. westos. 作业;
public class MyThread extends Thread {
public MyThread ( ) { }
public MyThread ( String name) {
super ( name) ;
}
@Override
public void run ( ) {
for ( int i = 0 ; i < 20 ; i++ ) {
String name1 = Thread. currentThread ( ) . getName ( ) ;
System. out. println ( name1 + "===" + i) ;
}
}
}
class ThreadTest2 {
public static void main ( String[ ] args) throws InterruptedException {
Thread t1 = new MyThread ( ) ;
Thread t2 = new MyThread ( ) ;
Thread t3 = new MyThread ( ) ;
t1. setName ( "monkey sun" ) ;
t2. setName ( "猪八戒" ) ;
t3. setName ( "唐僧" ) ;
t1. start ( ) ;
t1. join ( ) ;
t2. start ( ) ;
t2. join ( ) ;
t3. start ( ) ;
t3. join ( ) ;
}
}
礼让线程
public static void yield()
暂停当前正在执行的线程对象,并执行其他线程。
礼让是要暂停当前正在执行的线程,这个暂停的时间是相当短的,如果在这个线程暂停完毕以后,其他的线程还没有抢占到CPU的执行权,那么这个时候这个线程应该再次和其他线程抢占CPU的执行权.
守护线程
用户线程和守护线程的区别
用户线程和守护线程都是线程,区别是Java虚拟机在所有用户线程dead后,程序就会结束。而不管是否还有守护线程还在运行,若守护线程还在运行,则会马上结束。很好理解,守护线程是用来辅助用户线程的,如公司的保安和员工,各司其职,当员工都离开后,保安自然下班了。
创建守护线程
调用线程对象的方法setDaemon(true),设置线程为守护线程。
1)thread.setDaemon(true)必须在thread.start()之前设置。
2)在Daemon线程中产生的新线程也是Daemon的。
3)不是所有的应用都可以分配给Daemon线程来进行服务,比如读写操作或者计算逻辑。
因为Daemon Thread还没来得及进行操作,虚拟机可能已经退出了。
package org. westos. 作业;
public class ThreadTest3 {
public static void main ( String[ ] args) throws InterruptedException {
Thread. currentThread ( ) . setName ( "主线程唐僧" ) ;
for ( int i = 0 ; i < 10 ; i++ ) {
System. out. println ( Thread. currentThread ( ) . getName ( ) + "==" + i) ;
}
MyThread th1 = new MyThread ( ) ;
MyThread th2 = new MyThread ( ) ;
th1. setName ( "张飞" ) ;
th2. setName ( "关羽" ) ;
th1. setDaemon ( true ) ;
th2. setDaemon ( true ) ;
th1. start ( ) ;
th2. start ( ) ;
System. out. println ( Thread. currentThread ( ) . getName ( ) + "退出了" ) ;
}
}
class MyThread extends Thread {
public MyThread ( ) { }
public MyThread ( String name) {
super ( name) ;
}
@Override
public void run ( ) {
for ( int i = 0 ; i < 2000 ; i++ ) {
String name1 = Thread. currentThread ( ) . getName ( ) ;
System. out. println ( name1 + "===" + i) ;
}
}
}
中断线程
public final void stop(): 停止线程的运行
public void interrupt(): 中断线程,查看API可得当线程调用
wait(),sleep(long time) 方法的时候处于阻塞状态,可以通过这个方法清除阻塞
卖票
线程安全问题的产生原因:
否是多线程环境
是否有共享数据
是否有多条语句操作共享数据
解决线程安全:
使用同步代码块:
格式:
synchronized(对象){
//不能在括号了直接new 对象 new 了 就没效果
要被同步的代码 ;
}
package org. westos. 作业;
public class ThreadTest3 {
public static void main ( String[ ] args) {
MyRunnable mr = new MyRunnable ( ) ;
Thread t1 = new Thread ( mr, "窗口一" ) ;
Thread t2 = new Thread ( mr, "窗口二" ) ;
Thread t3 = new Thread ( mr, "窗口三" ) ;
t1. start ( ) ;
t2. start ( ) ;
t3. start ( ) ;
}
}
class MyRunnable implements Runnable {
static int ticket = 100 ;
static Object o = new Object ( ) ;
@Override
public void run ( ) {
while ( true ) {
synchronized ( o) {
if ( ticket > 0 ) {
try {
Thread. sleep ( 100 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
System. out. println ( Thread. currentThread ( ) . getName ( ) + "正在卖出第" + ( ticket-- ) + "票" ) ;
}
}
}
}
}
给方法上进行同步
同步代码块:锁对象是任意一个对象
同步方法:锁对象用的是this当前对象
静态同步方法:锁对象使用是当前字节码文件
package org. westos. 作业;
public class CellRunnable implements Runnable {
static int piao = 100 ;
static Object obj = new Object ( ) ;
int i = 1 ;
@Override
public void run ( ) {
while ( true ) {
if ( i % 2 == 0 ) {
synchronized ( this ) {
if ( piao >= 1 ) {
try {
Thread. sleep ( 50 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
System. out. println ( Thread. currentThread ( ) . getName ( ) + "正在出售第:" + ( piao-- ) + " 张票" ) ;
}
}
} else {
maiPiao ( ) ;
}
i++ ;
}
}
public synchronized void maiPiao ( ) {
if ( piao >= 1 ) {
try {
Thread. sleep ( 50 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
System. out. println ( Thread. currentThread ( ) . getName ( ) + "正在出售第:" + ( piao-- ) + " 张票" ) ;
}
}
}
lock锁
为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock
Lock和ReentrantLock
void lock() 加锁
void unlock() 释放锁
package org. westos. demo97;
import java. util. concurrent. locks. ReentrantLock;
public class CellRunnable implements Runnable {
static int piao = 100 ;
static ReentrantLock lock= new ReentrantLock ( ) ;
@Override
public void run ( ) {
while ( true ) {
lock. lock ( ) ;
try {
if ( piao >= 1 ) {
try {
Thread. sleep ( 50 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
System. out. println ( Thread. currentThread ( ) . getName ( ) + "正在出售第:" + ( piao-- ) + " 张票" ) ;
}
} catch ( Exception e) {
e. printStackTrace ( ) ;
} finally {
lock. unlock ( ) ;
}
}
}
}
死锁
如果出现了同步嵌套,就容易产生死锁问题
是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象
特点:
不出现异常
不会出现错误
程序一直僵持在呢里
package org. westos. demo99;
public class MyThread extends Thread {
boolean flag;
public MyThread ( boolean flag) {
this . flag = flag;
}
@Override
public void run ( ) {
if ( flag) {
synchronized ( ObjectUtils. objA) {
System. out. println ( "true 线程持有了objA锁,进来执行了AAAA" ) ;
synchronized ( ObjectUtils. objB) {
System. out. println ( "true 线程持有了objB锁,进来执行了BBB" ) ;
}
}
} else {
synchronized ( ObjectUtils. objB) {
System. out. println ( "false线程持有了objB锁,进来执行BBB" ) ;
synchronized ( ObjectUtils. objA) {
System. out. println ( "false 线程持有了objA锁,进来执行了AAA" ) ;
}
}
}
}
}
interface ObjectUtils {
public static final Object objA= new Object ( ) ;
public static final Object objB = new Object ( ) ;
}
class MyTest2 {
public static void main ( String[ ] args) throws InterruptedException {
MyThread th1 = new MyThread ( true ) ;
MyThread th2 = new MyThread ( false ) ;
th1. start ( ) ;
th2. start ( ) ;
}
}
public class DeadLock {
public static void main ( String[ ] args) {
Object o1 = new Object ( ) ;
Object o2 = new Object ( ) ;
Thread t1 = new MyThread1 ( o1, o2) ;
Thread t2 = new MyThread2 ( o1, o2) ;
t1. start ( ) ;
t2. start ( ) ;
}
}
class MyThread1 extends Thread {
Object o1;
Object o2;
public MyThread1 ( Object o1, Object o2) {
this . o1 = o1;
this . o2 = o2;
}
public void run ( ) {
synchronized ( o1) {
try {
Thread. sleep ( 1000 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
synchronized ( o2) {
}
}
}
}
class MyThread2 extends Thread {
Object o1;
Object o2;
public MyThread2 ( Object o1, Object o2) {
this . o1 = o1;
this . o2 = o2;
}
public void run ( ) {
synchronized ( o2) {
try {
Thread. sleep ( 1000 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
synchronized ( o1) {
}
}
}
}