多线程
并发执行的技术
并发和并行
并发:同一时间 有多个指令 在单个CPU上 交替执行
并行:同一时间 有多个指令 在多个CPU上 执行
进程和线程
进程:独立运行 任何进程 都可以同其他进程一起 并发执行
线程:是进程中的单个顺序控制流 是一条执行路径 线程又分为单线程和多线程
单线程:
多线程:JVM是多线程 其实就是JVM的主线程和垃圾回收线程在工作 结果在切换着运行
多线程的运行方式:他们拥有相等的运行权限 但运行过程是谁先抢到CPU的运行权限那么谁就先运行
线程的五种状态:新建,就绪,运行,堵塞,死亡
线程的实现:
方式一:继承Thread类
建立一个类继承Thread类 那么这类创建的对象可以并发的作为独立线程运行
继承的好处是可以使用父类中的方法 比较简单
继承的弊端是如果已经有父类了 就不可以再继承了 一个子类只能继承一个父类
public class Demo02 {
public static void main(String[] args) {
MyThread1 m1=new MyThread1();
MyThread2 m2=new MyThread2();
MyThread3 m3=new MyThread3();
//普通方法
/* m1.run();
m2.run();
m3.run();*/
//start开启新线程 内部会根据cpu的分配自动执行run
m1.start();
m2.start();
m3.start();//相当于跑步比赛的发令枪 启动后主线程与其他线程都会等待抢到cpu的执行权
//谁先抢到谁运行
}
}
//建立一个类继承Thread类 那么这类创建的对象可以并发的作为独立线程运行
class MyThread1 extends Thread{
public void run(){
for (int i = 0; i <10000000 ; i++) {
System.out.println("1号线程");
}
}
}
class MyThread2 extends Thread{
public void run(){
for (int i = 0; i <10000000 ; i++) {
System.out.println("2号线程");
}
}
}
class MyThread3 extends Thread{
public void run(){
for (int i = 0; i <10000000 ; i++) {
System.out.println("3号线程");
}
}
}
方式二:实现Runnable接口
建立一个类实现Runnable接口
接口的好处是就算实现了其他接口 也可以使用
接口的弊端 操作不便利 需要先获取Thread线程对象
public class Demo03 {
public static void main(String[] args) {
My1 my1=new My1();
Thread t1=new Thread(my1);
My2 my2=new My2();
Thread t2=new Thread(my2);
t1.start();
t2.start();
}
}
//定义一个类 实现Runnable接口 重新run方法
class My1 implements Runnable{
@Override
public void run() {
for (int i = 0; i <10000000 ; i++) {
System.out.println("1号线程");
}
}
}
class My2 implements Runnable{
@Override
public void run() {
for (int i = 0; i <10000000 ; i++) {
System.out.println("2号线程");
}
}
}
start()方法把当前线程交给了底层的 ThreadGroup group[]数组管理
Jvm根据随机分配的cpu执行权调用run() 随机分配的cpu执行权是相等概率的
匿名内部类实现线程
方式一:继承Thread类
public static void main(String[] args) {
new Thread(){
public void run(){
for(int i=0;i<10000000;i++){
new Student();
System.out.println("线程1");
}
}
}.start();
new Thread(){
public void run(){
for(int i=0;i<10000000;i++){
new Student();
System.out.println("线程2");
}
}
}.start();
}
方式二:实现Runnable接口
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <10000000 ; i++) {
System.out.println("1号线程");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <10000000 ; i++) {
System.out.println("2号线程");
}
}
}).start();
}
有名内部类实现线程
public static void main(String[] args) {
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <10000000 ; i++) {
System.out.println("1号线程");
}
}
});
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <10000000 ; i++) {
System.out.println("2号线程");
}
}
});
t1.start();
t2.start();
}
设置名字和获取名字(getName() setName())
可以在运行中获取当前线程的对象Thread.currentThread()
public class Demo06 {
public static void main(String[] args) {
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <10000000 ; i++) {
//Thread.currentThread()获取当前运行的线程对象
//获取名字getName()
System.out.println(Thread.currentThread().getName());
}
}
});
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <10000000 ; i++) {
System.out.println(Thread.currentThread().getName());
}
}
});
//设置名字
t1.setName("线程1");
t1.start();
t2.setName("线程2");
t2.start();
}
}
通过构造方法给线程取名
public class Demo06 {
public static void main(String[] args){
//通过构造方法给线程取名
Thread t1=new Thread(new M1(),"my1");
Thread t2=new Thread(new M2(),"my2");
t1.start();
t2.start();
}
}
class M1 implements Runnable{
@Override
public void run() {
for (int i = 0; i <100000 ; i++) {
System.out.println(Thread.currentThread().getName());
}
}
}
class M2 implements Runnable{
@Override
public void run() {
for (int i = 0; i <100000 ; i++) {
System.out.println(Thread.currentThread().getName());
}
}
}
休眠
Thread.sleep(100);让当前线程休眠100毫秒
class MM1 implements Runnable{
@Override
public void run() {
for (int i = 0; i <100000 ; i++) {
System.out.println(Thread.currentThread().getName());
try {
//让当前线程休眠100毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
守护线程
线程.setDaemon(true);
设置一个线程为守护线程 该线程不会单独执行 当其他非守护线程都执行结束后 再自动退出
public class Demo08 {
public static void main(String[] args) {
M2Thread m2=new M2Thread();
m2.setName("线程2");
m2.start();
M1Thread m1=new M1Thread();
m1.setName("线程1");
m1.start();
//守护线程不会单独执行
Thread1 t=new Thread1();
t.setName("守护线程");
t.setDaemon(true);//设置true为守护线程 主线程结束 守护线程也结束
t.start();
}
}
class M1Thread extends Thread{
public void run(){
for (int i = 0; i <100 ; i++) {
System.out.println(Thread.currentThread().getName());
}
}
}
class M2Thread extends Thread{
public void run(){
for (int i = 0; i <100 ; i++) {
System.out.println(Thread.currentThread().getName());
}
}
}
class Thread1 extends Thread{
public void run(){
for (int i = 0; i <10000 ; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
加入线程
线程.join(可以限定时间 也可以不限定);
public static void main(String[] args) {
Thread t1=new Thread("女朋友的电话"){
public void run(){
for (int i = 0; i <100 ; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
};
Thread t2=new Thread("老板的电话"){
public void run(){
for (int i = 0; i <100 ; i++) {
System.out.println(Thread.currentThread().getName()+i);
if(i==50){
try {
//加入女朋友的线程 基本全面占有cpu执行权
// t2线程要等待t1线程执行完毕后才可以继续执行
t1.join();//可以限定时间
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
};
t1.start();
t2.start();
}
礼让(了解)
Thread.yield();//让出cpu的执行权给别的线程
设置优先级:(优先级1-10 默认为5)
线程.setPriority(10);
同步(同步锁,同步代码块)
注意:开发中尽量不要嵌套同步代码块 可能会死锁
关键字:synchronized(同步锁使用的多)
public class Test {
String s="123";
//同步锁 在方法中加synchronized关键字
//public synchronized void show1(){}
public synchronized void show1(){
System.out.print("我");
System.out.print("爱");
System.out.print("学");
System.out.print("习");
System.out.println("-----------");
}
public void show2(){
//同步代码块synchronized(s锁对象){}
//多个同步代码块如果使用相同的锁对象 那么他们就是同步的
synchronized(s){
System.out.print("想");
System.out.print("睡");
System.out.print("觉");
System.out.println("===========");}
}
}
线程安全
synchronized线程安全 没有synchronized线程不安全
Vector线程安全 ArrayList线程不安全
Stringbuffer安全 stringBuilder不安全
HashTable安全 HashMap不安全
设计模式
单例设计模式
public class Single {
private Single(){//私有构造方法 不让其他类new对象
}
static Single s=new Single();
}
public static void main(String[] args) {
Single s1=Single.s;
Single s2=Single.s;
System.out.println(s1==s2);//true
Single s3=null;//对象可以被修改
Single s4=Single.s;
System.out.println(s3==s4);//false
}
饿汉式(直接加载)
节约时间 浪费空间(例如:安卓手机应用可以在后台运行)
一旦被加载进来 就创建好了对象 不管是否使用 都在内存中
public class Single1 {
private Single1(){//私有构造方法 不让其他类new对象
}
static Single1 s=new Single1();
//饿汉式
public static Single1 getInstance(){
//一旦被加载进来 就创建好了对象 不管是否使用 都在内存中
return s;
}
}
public static void main(String[] args) {
Single s1=Single.getInstance();
Single s2=Single.getInstance();
System.out.println(s1==s2);//true
}
懒汉式(延迟加载)
节约空间 浪费时间(例如:苹果手机应用不挂后台)
什么时候用 什么时候才创建
public class Single2 {
private Single2(){}
public static Single2 s=null;
//懒汉式
public static Single2 Instance(){
//需要的时候才创建对象
if(s==null){
s=new Single2();
}
return s;
}
}
Runtime类单例(查API)
每个 Java 应用程序都有一个Runtime
类实例 使应用程序能够与其运行的环境相连接 可以通过 getRuntime
方法获取当前运行时。
应用程序不能创建自己的 Runtime
类实例
public static void main(String[] args) {
Runtime r=Runtime.getRuntime();
try {
//r.exec("mspaint");//打开画图
//r.exec("notepad");//打开记事本
//r.exec("shutdown -s -t 6000");//6000秒后自动关机
//r.exec("shurdown -a");//取消自动关机
//r.exec("百度去");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Timer类(计时器)
用来定时执行程序的类
public class MyTask extends TimerTask {
@Override
public void run() {
System.out.println("起床了");
}
}
public static void main(String[] args) {
//用来定时执行程序的类
Timer t=new Timer();
//5秒后执行任务
t.schedule(new MyTask(),new Date(System.currentTimeMillis()+5000));
//5秒后执行任务 每隔1秒重复执行
t.schedule(new MyTask(),new Date(System.currentTimeMillis()+5000),1000);
}
线程通信(等待,唤醒)
必须在同步代码块中 使用同步锁对象调用(唤醒 等待 唤醒 等待)代码交替运行
并发执行时 默认情况下 cpu的执行权 是随机的 谁先抢到谁先执行
如果希望有规律的执行 就可以用线程通信
notify唤醒 wait等待
案例:两个方法交替
public class TestThread2 {
public synchronized void print(){
System.out.print("我");
System.out.print("爱");
System.out.print("学");
System.out.print("习");
System.out.println("-----------");
this.notify();//唤醒正在等待的线程
try {
this.wait();//让当前线程等待 让出cpu执行权 进入就绪状态
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public synchronized void show(){
System.out.print("想");
System.out.print("睡");
System.out.print("觉");
System.out.println("===========");
this.notify();//唤醒正在等待的线程
try {
this.wait();//让当前线程等待 让出cpu执行权 进入就绪状态
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
TestThread2 tt2=new TestThread2();
new Thread(){
public void run(){
while(true){ tt2.print();}
}
}.start();
new Thread(){
public void run(){
while(true){ tt2.show();}
}
}.start();
}
案例:三个和三个以上方法交替
public class TestThread3 {
boolean b1=true;
boolean b2=false;
boolean b3=false;
public synchronized void show1() {
if (b3) {
System.out.print("我");
System.out.print("爱");
System.out.print("学");
System.out.print("习");
System.out.println("-----------");
}
b1 = true;
b3 = false;
this.notifyAll();//唤醒所有正在等待的线程
try {
this.wait();//让当前线程等待 让出cpu执行权 进入就绪状态
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public synchronized void show2(){
if(b1){
System.out.print("想");
System.out.print("睡");
System.out.print("觉");
System.out.println("===========");
}
b2=true;
b1=false;
this.notifyAll();//唤醒所有正在等待的线程
try {
this.wait();//让当前线程等待 让出cpu执行权 进入就绪状态
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public synchronized void show3(){
if(b2){
System.out.print("想");
System.out.print("吃");
System.out.print("饭");
System.out.println("~~~~~~~~~~~");
}
b2=false;
b3=true;
this.notifyAll();//唤醒所有正在等待的线程
try {
this.wait();//让当前线程等待 让出cpu执行权 进入就绪状态
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
TestThread3 tt3=new TestThread3();
new Thread(){
public void run(){
while(true){
tt3.show1();
}
}
}.start();
new Thread(){
public void run(){
while(true){
tt3.show2();
}
}
}.start();
new Thread(){
public void run(){
while(true){
tt3.show3();
}
}
}.start();
}
wait和sleep区别
wait():释放锁 等待并释放锁让别的线程运行
sleep():不释放锁 在指定的时间抱着锁睡 时间一到马上醒来