多线程
进程:正在运行的程序。
线程:进程的一个执行单元,一条路径
1.1 多线程的创建
线程是程序中的执行线程。Java虚拟机允许应用程序并发地运行多个执行线程
1.1.1 方式1
将类申明为java.lang包下Thread的子类,该子类重写Thread类的run方法,实例化子类对象并启动线程
public final String getName() 返回该线程的名称
public final void setName(String name) 设置线程的名称
1.1.2 方法2
声明实现java.lang包下Runnable接口的类,该类重写run方法,实例化该类对象,在创建Thread对象时作为一个参数进行传递并启动
public static Thread currentThread() 返回当前正在执行线程的对象引用
1.1.3 继承Thread类与实现Runnable接口方式的区别
避免单继承的局限性;实现接口方式,只创建了一个资源对象,更好地实现了数据和操作的分离。一般选择实现接口的方式创建多线程
1.2 线程的生命周期
新建状态---------就绪状态---------阻塞状态()---------运行状态---------死亡状态
线程的创建(两种方式:一个类继承Thread类,一个类实现Runnable接口)
继承Thread类方式:
public class MyThread extends Thread {
@Override
public void run() {
for(int x=0;x<10;x++){
System.out.println(getName()+"---hello"+x);
}
}
}
public class ThreadTest {
public static void main(String[] args) {
//创建多线程对象
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
//设置线程名称
mt1.setName("Nina");
mt2.setName("Lucy");
//启动线程
mt1.start();
mt2.start();
}
}
实现Runnable接口方式:
public class MyRunnable implements Runnable{
@Override
public void run() {
for(int x=1;x<11;x++){
System.out.println(Thread.currentThread().getName()+"---hello"+x);
}
}
}
public class MyRunnableTest {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
t1.setName("中国地");
t2.setName("闯关东");
t1.start();
t2.start();
}
}
两种方式下的火车站窗口出售火车票
继承Thread类方式:
public class TicketThread extends Thread{
//票资源
private static int tickets = 20;
@Override
public void run() {
while(true){
if(tickets>0){
System.out.println(getName()+"正在出售第"+tickets--+"张票");
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
//创建四个窗口--启动四个线程
TicketThread tt1 = new TicketThread();
TicketThread tt2 = new TicketThread();
TicketThread tt3 = new TicketThread();
TicketThread tt4 = new TicketThread();
//设置线程名称
tt1.setName("窗口1");
tt2.setName("窗口2");
tt3.setName("窗口3");
tt4.setName("窗口4");
//启动线程
tt1.start();
tt2.start();
tt3.start();
tt4.start();
}
}
实现Runnable方式:
public class TicketsRunnable implements Runnable{
private int tickets =20;
public void run() {
while(true){
if(tickets>0){
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets--+"张票");
}
}
}
}
public class TicketThreadTest {
public static void main(String[] args) {
TicketsRunnable tr = new TicketsRunnable();
Thread t1 = new Thread(tr);
Thread t2 = new Thread(tr);
Thread t3 = new Thread(tr);
Thread t4 = new Thread(tr);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t4.setName("窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
实现Runnable接口方式下加入Thread.sleep(100)操作语句,出现的问题:相同票数、0票和负数票
public class TicketsRunnable implements Runnable {
private int tickets =100;
@Override
public void run() {
while(true){
if(tickets>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets--+"张票");
}
}
}
}
public class RunnableTest {
public static void main(String[] args) {
TicketsRunnable tr = new TicketsRunnable();
Thread t1 = new Thread(tr);
Thread t2 = new Thread(tr);
Thread t3 = new Thread(tr);
Thread t4 = new Thread(tr);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t4.setName("窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
线程出问题的判断条件:有没有共享资源,对共享资源的操作是否有多条语句,是不是在多线程中
解决方案:同步代码块(同步机制) 锁对象:任意锁对象(同一把锁)(synchronized(锁对象){有问题的代码})
public class TicketsRunnable implements Runnable {
private int tickets = 100;
private Object obj = new Object();
@Override
public void run() {
while (true) {
// 同步机制
synchronized (obj) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + tickets-- + "张票");
}
}
}
}
}
public class RunnableTest {
public static void main(String[] args) {
TicketsRunnable tr = new TicketsRunnable();
Thread t1 = new Thread(tr);
Thread t2 = new Thread(tr);
Thread t3 = new Thread(tr);
Thread t4 = new Thread(tr);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t4.setName("窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
同步方法 锁对象:this对象(把synchronized加在方法上)
public class TicketsRunnable implements Runnable {
private int tickets =100;
@Override
public void run() {
int x = 0;
while (true) {
if (x % 2 == 0) {
synchronized (this) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + tickets-- + "张票");
}
}
}else{
check();
}
}
}
//方法,锁加在方法上
private synchronized void check(){
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + tickets-- + "张票");
}
}
}
public class RunnableTest {
public static void main(String[] args) {
TicketsRunnable tr = new TicketsRunnable();
Thread t1 = new Thread(tr);
Thread t2 = new Thread(tr);
Thread t3 = new Thread(tr);
Thread t4 = new Thread(tr);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t4.setName("窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
静态同步方法 锁对象:类名.class-- Class文件对象
public class TicketsRunnable implements Runnable {
private static int tickets = 100;
@Override
public void run() {
int x = 0;
while (true) {
if (x % 2 == 0) {
synchronized (TicketsRunnable.class) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + tickets-- + "张票");
}
}
}else{
check();
}
}
}
//方法,锁加在方法上
private static synchronized void check() {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + tickets-- + "张票");
}
}
}
public class RunnableTest {
public static void main(String[] args) {
TicketsRunnable tr = new TicketsRunnable();
Thread t1 = new Thread(tr);
Thread t2 = new Thread(tr);
Thread t3 = new Thread(tr);
Thread t4 = new Thread(tr);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t4.setName("窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
死锁问题
用实现Runable接口方式实现:
public class DeadLockThread implements Runnable {
private boolean flag;
public DeadLockThread(boolean flag) {
this.flag = flag;
}
//被static修饰的内容被所有对象共享
private static Object objA = new Object();
private static Object objB = new Object();
@Override
public void run() {
if (flag) {
while (true) {
synchronized (objA) {
// dt1进来了
System.out.println(Thread.currentThread().getName()
+ "--if--objA");
synchronized (objB) {
System.out.println(Thread.currentThread().getName()
+ "--if--objB");
}
}
}
} else {
while (true) {
synchronized (objB) {
// dt2进来了
System.out.println(Thread.currentThread().getName()
+ "--else--objB");
synchronized (objA) {
System.out.println(Thread.currentThread().getName()
+ "--else--objA");
}
}
}
}
}
}
public class DeadLockThreadTest {
public static void main(String[] args) {
DeadLockThread dt1 = new DeadLockThread(true);
DeadLockThread dt2 = new DeadLockThread(false);
Thread t1 = new Thread(dt1);
Thread t2 = new Thread(dt2);
t1.setName("小乔");
t2.setName("范明");
t1.start();
t2.start();
}
}
用继承Thread类方式实现:
public class MyLock {
public static final Object objA =new Object();
public static final Object objB = new Object();
}
public class DeadLock extends Thread{
private boolean flag;
public DeadLock(boolean flag){
this.flag = flag;
}
@Override
public void run() {
if(flag){
while(true){
synchronized(MyLock.objA){
System.out.println(Thread.currentThread().getName()+"--if--objA");
synchronized(MyLock.objB){
System.out.println(Thread.currentThread().getName()+"--if--objB");
}
}
}
}else{
while(true){
synchronized(MyLock.objB){
System.out.println(Thread.currentThread().getName()+"--else--objB");
synchronized(MyLock.objA){
System.out.println(Thread.currentThread().getName()+"--else--objA");
}
}
}
}
}
}
public class DeadLockTest {
public static void main(String[] args) {
DeadLock d1 = new DeadLock(true);
DeadLock d2 = new DeadLock(false);
d1.setName("小乔");
d1.setName("范明");
d1.start();
d2.start();
}
}
线程间的通信问题
public class Student {
//这里不能加private修饰符,private修饰符只能在本类中使用
String name;
int age;
}
//创建多线程
public class SetStudent implements Runnable {
private Student s;
public SetStudent(Student s) {
this.s = s;
}
// 设置学生属性
@Override
public void run() {
int x = 0;
while (true) {
if (x % 2 == 0) {
s.name="小乔";
s.age=18;
}else{
s.name="范明";
s.age =26;
}
x++;
}
}
}
//创建多线程
public class GetStudent implements Runnable {
private Student s;
public GetStudent(Student s){
this.s =s;
}
@Override
public void run() {
while(true){
System.out.println(s.name+"***"+s.age);
}
}
}
public class StudentTest {
public static void main(String[] args) {
Student s = new Student();
SetStudent ss = new SetStudent(s);
GetStudent gs = new GetStudent(s);
Thread t1 = new Thread(ss);
Thread t2 = new Thread(gs);
t1.start();
t2.start();
}
}
由于线程的随机性产生的问题。
判断线程是否出现问题的依据:
A:是否有共享数据
B:是否有多条语句操作共享数据
C:是否在多线程环境中
解决方法:
用同步解决。
加入同步代码块解决通信问题
public class Student {
String name;
int age;
}
public class SetStudent implements Runnable {
private Student s;
public SetStudent(Student s) {
this.s = s;
}
@Override
public void run() {
int x=0;
while(true){
//使用同步(同步代码块,锁对象为同一把锁)
synchronized(s){
if(x%2==0){
s.name = "小乔";
s.age =18;
}else{
s.name ="范明";
s.age =26;
}
x++;
}
}
}
}
public class GetStudent implements Runnable{
private Student s;
public GetStudent(Student s){
this.s =s;
}
@Override
public void run() {
while(true){
synchronized(s){
System.out.println(s.name+"***"+s.age);
}
}
}
}
public class GetStudent implements Runnable{
private Student s;
public GetStudent(Student s){
this.s =s;
}
@Override
public void run() {
while(true){
synchronized(s){
System.out.println(s.name+"***"+s.age);
}
}
}
}
public class StudentTest {
public static void main(String[] args) {
Student s = new Student();
SetStudent ss = new SetStudent(s);
GetStudent gs = new GetStudent(s);
Thread t1 = new Thread(ss);
Thread t2 = new Thread(gs);
t1.start();
t2.start();
}
}
11 等待唤醒机制解决线程通信问题
public final void wait():线程等待
public final void notify():唤醒线程
public class Student {
String name;
int age;
//flag作为数据标识,true表示有数据,false表示没有数据
boolean flag=false;
}
public class SetStudent implements Runnable {
private Student s;
public SetStudent(Student s) {
this.s = s;
}
@Override
public void run() {
int x = 0;
while (true) {
synchronized (s) {
//没有数据,等待设置数据
if (s.flag) {
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (x % 2 == 0) {
s.name = "小乔";
s.age = 18;
} else {
s.name = "范明";
s.age = 26;
}
x++;
}
s.flag =true;
s.notify();
}
}
}
}
public class GetStudent implements Runnable {
private Student s;
public GetStudent(Student s) {
this.s = s;
}
@Override
public void run() {
while (true) {
synchronized (s) {
//没有数据,等待设置获取
if (!s.flag) {
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(s.name + "****" + s.age);
}
s.flag = false;
s.notify();
}
}
}
}
public class StudentTest {
public static void main(String[] args) {
Student s = new Student();
GetStudent ss = new GetStudent(s);
SetStudent gs = new SetStudent(s);
Thread t1 = new Thread(ss);
Thread t2 = new Thread(gs);
t1.start();
t2.start();
}
}
加入同步方法解决通信问题
public class Student {
String name;
int age;
boolean flag = false;
//设置属性方法
public synchronized void set(String name,int age){
//没有数据,等待设置
if(this.flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.name =name;
this.age =age;
}
//修改标记
this.flag =true;
this.notify();
}
//获取属性方法
public synchronized void get(){
if(!this.flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.name+"****"+this.age);
}
//修改标记
this.flag =false;
this.notify();
}
}
public class SetStudent implements Runnable{
private Student s;
public SetStudent(Student s){
this.s = s;
}
@Override
public void run() {
int x=0;
while(true){
if(x%2==0){
s.set("小乔",18);
}else{
s.set("范明", 26);
}
x++;
}
}
}
public class GetStudent implements Runnable {
private Student s;
public GetStudent(Student s){
this.s = s;
}
@Override
public void run() {
while(true){
s.get();
}
}
}
public class StudentTest {
public static void main(String[] args) {
Student s = new Student();
SetStudent ss = new SetStudent(s);
GetStudent gs = new GetStudent(s);
Thread t1 = new Thread(ss);
Thread t2 = new Thread(gs);
t1.start();
t2.start();
}
}
守护线程:
public final void setDaemon(boolean on):设置线程为守护线程,一旦前台线程(主线程)结束,守护线程就结束。
插入线程:
public final void join();一旦有join()线程,那么,当前线程必须等待,直到该线程结束。
线程的优先级(线程默认优先级是5,范围为1-10):
public final int getPriority():获取线程的优先级
public final void setPriority(int newPriority):更改线程的优先级
线程让步:
public final void yield():暂停当前正在执行的线程对象,并执行其他线程。