JAVA-进程与线程及线程池

进程

进程就是正在进行的程序,因为同一时间点计算机只能执行一个进程 ,计算机在不同的进程中快速的切换来达到多进程

多进程的意义:多进程的作用是提高CPU的使用率,而不是提高执行速度

线程

在一个进程中可以执行多个任务,而每一个任务可以看做一个线程

多线程的意义:多线程是为了提高应用程序的使用率,而不是提高执行速率

程序在运行过程中,都是在抢CPU的执行权,而且是随机的

并行和并发:

并行:某一时间段内同时运行多个程序

并发:某一时间点同时运行多个程序

启动JVM就是一个多线程的例子,会自动启动一个主线程,并用主线程调用main方法,所以多线程应该至少有一个主线程,一个垃圾回收线程

线程的两种开启方式

一,继承Thread类

package org.westos.demo2;

public class MyTest2 {
    public static void main(String[] args) {
        
        Thread thread = Thread.currentThread();
        thread.setName("主线程");
        System.out.println(thread.getName());
        MyThread2 th1 = new MyThread2();
        th1.setName("范冰冰");
        MyThread2 th2 = new MyThread2();
        th2.setName("李冰冰");
        th1.start();
        th2.start();
    }
}
package org.westos.demo2;

public class MyThread2 extends Thread{
    @Override
    public void run() {//run方法中一般放比较费时的操作
        super.run();
        for(int i=0;i<100;i++){
            //this.getName() 获取当前线程的名称
            //Thread.currentThread() 获取当前正在执行的线程
            Thread thread = Thread.currentThread();
            System.out.println(thread.getName()+i);
        }
    }
}

二,实现Rannable方法

package org.westos.demo;

public class MyTest {

	public static void main(String[] args) {
		
		MyThread th = new MyThread();
		th.start();//开启方式1
		//th.start(); 注意不要重复的去开启线程
		//开启方式2:new Thread(new MyThread2()).start();
	}

}
package org.westos.demo;

public class MyThread2 implements Runnable {

	@Override
	public void run() {
		System.out.println("线程要执行的代码");
		
	}

}

getName()获取当前线程的名称

currentThread()获取当前正在执行的线程

setPriority()设置线程优先级,括号中写优先级别1-10,默认优先级都是5

getPriority()获取线程优先级

sleep()线程休眠,括号中写休眠时长,毫秒,一般会出现异常,需要处理

join()线程加入,一般要在线程开启之后再加入,线程加入表示等待该线程执行完毕后,其他线程才能再次执行

yield()礼让线程,暂停正在执行的线程对象,并执行其他线程,这个方法必须在开启线程前调用

setDaemon() 设置为守护线程,这个方法必须在开启线程前调用

package org.westos.demo;

public class MyTest {
    public static void main(String[] args) {

//        将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
//        该方法必须在启动线程前调用。
        String name = Thread.currentThread().getName();
        System.out.println(name);
        MyThread th1 = new MyThread();
        MyThread th2 = new MyThread();
        th1.setName("关羽");
        th2.setName("张飞");
        th1.setDaemon(true);//将该线程设置为守护线程
        th2.setDaemon(true);
        th1.start();
        th2.start();
    }
}
class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 100; i++) {
            System.out.println(this.getName() + "===" + i);
        }
    }
}
interrupt()  打断线程阻塞状态,会抛出异常

采用匿名内部类的方法开启线程

package org.westos.demo91;

public class MyTest91 {
    public static void main(String[] args) {
        //采用匿名内部类的方式来开启线程
        //方式1
        new Thread(){
            @Override
            public void run() {
                super.run();
                System.out.println("线程开启了");
            }
        }.start();
        //方式2
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程2开启了");
            }
        }).start();
        //Java1.8 Lambda表达式
        Runnable ra=()->{
            System.out.println("线程3开启了");
        };
        new Thread(ra).start();

        new Thread(()->{
            System.out.println("线程4开启了");
        }).start();


    }
}
案例:三个窗口同时出售100张票
package org.westos.demo92;

public class MyTest92 {
    public static void main(String[] args) {
        MyThread92 mt1 = new MyThread92();
        MyThread92 mt2 = new MyThread92();
        MyThread92 mt3 = new MyThread92();
        Thread th1 = new Thread(mt1,"窗口1");
        Thread th2 = new Thread(mt2,"窗口2");
        Thread th3 = new Thread(mt3,"窗口3");
        th1.start();
        th2.start();
        th3.start();
    }
}

class MyThread92 implements Runnable {
    private static int tickets = 100;//多个线程共享数据

    @Override
    public void run() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        while (true) {
            if (tickets > 0) {
                System.out.println(Thread.currentThread().getName() + "正在出售" + (tickets--) + "张票");
            }
        }
    }
}

可能产生数据安全的条件

一,多线程环境

二,有共享数据

三,有多条语句共同操作共享数据


处理数据安全有三种方法

1,加同步代码块(锁对象可以使用任意对象,但锁对象要让多个线程共享)

package org.westos.demo4;
public class MyThread4 implements Runnable{
	private static int piao=100;//共享数据,多个线程共享此数据
	private static final Object obj=new Object();//锁对象要共享
	@Override
	public void run() {
		//同步代码块:参数里面要一个锁,这个锁传任意一个对象 注意 加的这个锁对象,一定要让多个线程去共享
			while (true) {
				//1 2 3
				synchronized (obj) {//同步代码块  参数就是一个锁对象
					//单线程环境
					try {
						//模拟网络延迟
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					if(piao>0) {
						System.out.println(Thread.currentThread().getName()+"正在出售"+(piao--)+"张票");
					}
				}
				
			}
	}

}

2,使用同步方法(锁所对象是this)

3,静态同步方法(锁对象是当前类的字节码文件对象)

package org.westos.demo5;

public class MyThread5 implements Runnable {

	private static int piao = 100;// 共享数据,多个线程共享此数据
	private static final Object obj = new Object();// 锁对象要共享
	int n = 0;
	
	@Override
	public void run() {
		// 同步方法:他的锁对象是this
		//静态同步方法的锁对象是:当前类的字节码文件对象
		while (true) {
			
			if (n % 2 == 0) {
				synchronized (MyThread5.class) {// 同步代码块 参数就是一个锁对象
					// 单线程环境
					try {
						// 模拟网络延迟
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					if (piao > 0) {
						System.out.println(Thread.currentThread().getName() + "正在出售" + (piao--) + "张票");
					}
				}

			} else {

				//maipiao();
				maipiao2();

			}
			// 1 2 3
			n++;
		}
	}
	//静态同步方法
	private static synchronized void maipiao2() {
		// 单线程环境
		try {
			// 模拟网络延迟
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if (piao > 0) {
			System.out.println(Thread.currentThread().getName() + "正在出售" + (piao--) + "张票");

		}
		
	}

	// 同步方法:将 synchronized 加到方法上
	private synchronized void maipiao() {

		// 单线程环境
		try {
			// 模拟网络延迟
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if (piao > 0) {
			System.out.println(Thread.currentThread().getName() + "正在出售" + (piao--) + "张票");

		}

	}

}
4,上锁和解锁
package org.westos.demo6;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyThread6 implements Runnable{
	
	private static int piao=100;//共享数据,多个线程共享此数据
	Lock lock=new ReentrantLock();
	@Override
	public void run() {
		while (true) {
			lock.lock();//加锁
			try {
				//模拟网络延迟
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			if(piao>0) {
				System.out.println(Thread.currentThread().getName()+"正在出售"+(piao--)+"张票");
				
			}
			//释放锁
			lock.unlock();
		}	
	}
}

死锁现像

出现同步嵌套,就容易产生死锁现象,两个或两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待的现象

package org.westos.demo7;

public interface MyLock {
	//定义两个锁对象
	public static final Object objA=new Object();
	public static final Object objB=new Object();

}
package org.westos.demo7;

public class MyTest7 {

	public static void main(String[] args) {
		
		MyThread7 th1 = new MyThread7(true);
		MyThread7 th2 = new MyThread7(false);
		th1.start();
		th2.start();
	}

}
package org.westos.demo7;

public class MyThread7 extends Thread {
	boolean flag = true;

	public MyThread7(boolean flag) {
		super();
		this.flag = flag;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
		if (flag) {
			synchronized (MyLock.objA) {
				System.out.println("第一层进来了" + "A");
				synchronized (MyLock.objB) {
					System.out.println("第二层进来了" + "B");
				}
			}

		} else {
			synchronized (MyLock.objB) {
				System.out.println("第一层进来了" + "B");
				synchronized (MyLock.objA) {
					System.out.println("第二层进来了" + "A");
				}
			}
		}

	}

}

 线程池:高效的管理多个线程的容器

JDK1.5之后用Executors工厂类来生产线程池,Executors有以下几个方法

1。   public static ExecutorsService newCachdThreadPool()

根据任务的数量来创建对应的线程个数 

package org.westos.demo;

import java.util.concurrent.ExecutorService;

public class MyRannable implements Runnable {
    ExecutorService single;

    public MyRannable(ExecutorService single) {
        super();
        this.single=single ;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"需要执行的代码");
    }
}
package org.westos.demo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test3 {
    public static void main(String[] args) {
        ExecutorService cached = Executors.newCachedThreadPool();
        //根据任务的数量来创建线程对应的线程个数
        cached.submit(new MyRannable(cached));
        cached.submit(new MyRannable(cached));
        cached.submit(new MyRannable(cached));
        cached.submit(new MyRannable(cached));
        cached.submit(new MyRannable(cached));
        cached.submit(new MyRannable(cached));
        cached.submit(new MyRannable(cached));
        cached.shutdown();
    }
}

2。     public static ExecutorsService newFixedThreadPool(int nThreads)

固定初始化几个线程

package org.westos.demo;

import java.util.concurrent.*;

public class Test2 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //固定初始化几个线程
        ExecutorService fix = Executors.newFixedThreadPool(3);
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {

                System.out.println(Thread.currentThread().getName() + "任务执行了");

                return "任务执行完了";//Callable接口会返回执行结果
            }
        };
        Future<String> submit1 = fix.submit(callable);
        Future<String> submit2 = fix.submit(callable);
        Future<String> submit3 = fix.submit(callable);
        Future<String> submit4 = fix.submit(callable);
        Future<String> submit5 = fix.submit(callable);
        Future<String> submit6 = fix.submit(callable);
        String s = submit1.get();
        System.out.println(s+"hahaha");
        fix.shutdown();
    }
}

3。    public static ExecutorsService newSingleThreadPool()

初始化一个线程的线程池

package org.westos.demo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {
    public static void main(String[] args) {
        //初始化一个线程的线程池
        ExecutorService single = Executors.newSingleThreadExecutor();
        single.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("任务执行了");
            }
        });
        single.shutdown();
    }
}


CallableRunnable的区别
相同点:
    两者都是接口
    两者都可用来编写多线程程序
    两者都需要调用Thread.start()启动线程
不同点:
    两者最大的不同点是
     实现Callable接口的任务线程能返回执行结果
     而实现Runnable接口的任务线程不能返回结果
     Callable接口的call()方法允许抛出异常
     而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛










猜你喜欢

转载自blog.csdn.net/xiongzhouxiong/article/details/79436498