多线程
并行与并发
- 并发、两个或多个时间同一时间段内发生----交替执行,段时间
- 并行、两个或多个时间同一时刻内发生----同时发生
线程与进程 - 进入到内存的程序叫进程
- 线程属于进程,是进程中的一个执行单元,负责程序的执行
- 主线程:执行主方法,main方法的路径
创建多线程
①创建Thread的子类 - 创建一个Thread的子类
- 在Thread大的子类中重写Run方法,设置线程任务
- 此案件Thread的子类对象
- 调用Thread类中的方法Strat方法,开启新的线程,执行run方法
public class Method1Thread extends Thread{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(i+"i");
}
}
}
package java16;
public class Method1ThreadMain {
public static void main(String[] args) {
Method1Thread m=new Method1Thread();
m.start();
for(int i=0;i<20;i++) {
System.out.println("main"+i);
}
}
}
②实现Runnable接口
- 创建一个Runnable接口的实现类
- 实现类中重写Runnable接口的run方法,设置线程任务
- 创建一个Runnable类的实现对象
- 创建Thread类对象,构造方法中传递Runnable接口实现类对象
- 调用Thread类中的Start方法,开始心线程执行run方法
package java16;
public class RunnableImple implements Runnable{//创建一个Runnable接口的实现类
@Override
public void run() {//实现类中重写Runnable接口的run方法,设置线程任务
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
package java16;
public class RunnableMain {
public static void main(String[] args) {
RunnableImple r=new RunnableImple();//创建一个Runnable类的实现对象
Thread t=new Thread(r);//创建Thread类对象,构造方法中传递Runnable接口实现类对象
t.start();//调用Thread类中的Start方法,开始心线程执行run方法
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
区别
- 第二种方法,避免了单继承的局限性,接口的实现还可以继承与实现其他父类或接口
- 增强了程序扩展性,降低耦合性,Thread接受什么,可以开启不同的新线程
匿名内部类创建新线程
package java16;
public class InnerClassThreadMain {
public static void main(String[] args) {
// 匿名内部类1
new Thread() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(getName()+"i:"+i);
}
}
}.start();
//
// for (int j = 0; j < 20; j++) {
// System.out.println(Thread.currentThread().getName()+j);
//
// }
//匿名内部类2
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(i+"------2");
}
}
}).start();
//匿名内部类2原例子 RunnableMain
}
}
Tread的常用方法
获取线程名字
- getname
- 先获取正在执行的线程 currentThread 然后用getname
package java16;
public class MyThread extends Thread{
@Override
public void run() {
// String name = getName();
// System.out.println(name);
//
// Thread t = new Thread();
// Thread currentThread = Thread.currentThread();
// String name = currentThread.getName();
// System.out.println(name);
System.out.println(Thread.currentThread().getName());
}
}
package java16;
public class ThreadMain {
public static void main(String[] args) {
MyThread m=new MyThread();
m.start();//thread-0
new MyThread().start();//Thread-1
new MyThread().start();//Thread-2
System.out.println(Thread.currentThread().getName());
}
}
修改线程的名字
- setname直接修改
- 使用构造方法,带参数的,使用父类的方法给子类赋值
停止当前线程
public static void sleep(long millis)
结束之后继续执行
线程安全
解决线程安全方法
①:使用同步代码块
synchronized(锁对象){ 可能会出现线程安全的代码}
会降低效率
注意:
- 锁对象可以使用任意对象
- 但必须保证多个线程的锁对象是同一个
- 锁对象作用:
把同步代码块锁住,只让一个线程执行
package java16;
public class MaiPiao implements Runnable{
private int ticket=100;
Object o=new Object(); //锁对象
@Override
public void run() {
for (int i = 0; i < 999; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (o) { 同步代码块
if (ticket>0) {
System.out.println(Thread.currentThread().getName()+"---------------正在卖"+ticket+"张");
ticket--;
}
}
}
}
}
package java16;
public class MaiPiaoMain {
public static void main(String[] args) {
MaiPiao m=new MaiPiao();
Thread t1=new Thread(m);
Thread t2=new Thread(m);
Thread t3=new Thread(m);
t1.start();
t2.start();
t3.start();
}
}
②:同步方法
- 把访问了共享数据的代码抽取出来,放到一个方法中
- 在方法上添加修饰符synchronized
package java16_1;
//同步方法
public class MaiPiao implements Runnable{
private /*static*/int ticket=100;
@Override
public void run() {
for (int i = 0; i < 999; i++) {
// if (ticket>0) {
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName()+"---------------正在卖"+ticket+"张");
// ticket--;
//
// }
method1();//同步方法//静态同步方法
}
}
public /*static*/synchronized void method1() {
// synchronized (this) {
if (ticket>0) {
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
System.out.println(Thread.currentThread().getName()+"---------------正在卖"+ticket+"张");
ticket--;
}
// }
}
}
package java16_1;
public class MaiPiaoMain {
public static void main(String[] args) {
MaiPiao m=new MaiPiao();
Thread t1=new Thread(m);
Thread t2=new Thread(m);
Thread t3=new Thread(m);
t1.start();
t2.start();
t3.start();
}
}
③:Lock锁
- 在成员位置创建一个ReentrantLock对象
- 在可能出现的安全问题之前调用Lock接口中的方法lock获取锁
- 在可能出现的安全问题后调用unlock方法释放锁
package java16_2;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MaiPiao implements Runnable{
private int ticket=100;
Lock l=new ReentrantLock();
@Override
public void run() {
for (int i = 0; i < 999; i++) {
l.lock(); //获取锁
if (ticket>0) {
System.out.println(Thread.currentThread().getName()+"---------------正在卖"+ticket+"张");
ticket--;
}
l.unlock(); //释放锁
}
}
}
package java16_2;
public class MaiPiaoMain {
public static void main(String[] args) {
MaiPiao m=new MaiPiao();
Thread t1=new Thread(m);
Thread t2=new Thread(m);
Thread t3=new Thread(m);
t1.start();
t2.start();
t3.start();
}
}
等待唤醒----wait/notify
线程之间的通信
package java16;
public class WaitAndNotify {
public static void main(String[] args) {
Object obj=new Object();//创建锁对象
new Thread() {
public void run() {
while(true) {
synchronized (obj) {
System.out.println("老板我要xx个包子");
try {
obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("吃包子");
System.out.println("------------------------");
}
}
};
}.start();
new Thread() {
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (obj) {
System.out.print("花了五秒 做好了--------------");
System.out.println("可以吃了");
obj.notify();
}
}
};
}.start();
}
}
线程池
package java16.ThreadPool;
public class RunnbleImples implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"创建了新线程");
}
}
package java16.ThreadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java16.RunnableImple;
//线程池的代码实现
public class ThreadPoolMain {
public static void main(String[] args) {
//创建一定数量的线程池 2个
ExecutorService es = Executors.newFixedThreadPool(2);
//调用submit方法,执行run方法
//两个线程 重复使用
es.submit(new RunnbleImples());
es.submit(new RunnbleImples());
es.submit(new RunnbleImples());
//销毁线程池
es.shutdown();
//没了线程池,报错
// es.submit(new RunnbleImples());
}
}
/*
pool-1-thread-1创建了新线程
pool-1-thread-2创建了新线程
pool-1-thread-2创建了新线程
*/