程序,进程,线程
- 程序:为完成特定任务,使用某种语言编写的一组指令的集合,是一段静态的代码。
- 进程:程序的一次运行过程,或者是正在运行的一个程序。进程是资源分配的基本单位。
- 线程:线程由进程进一步细化而来,是一个程序内部的一条执行路径。线程是调度和执行的单位,每个线程拥有独立的运行栈和程序计数器,线程开销很小。
Thread生命周期
Thread类中的常用方法
- start():启动当前线程;调用当前线程的run()。
- run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中。
- currentThread():静态方法,返回执行当前代码的线程。
- getName():获取当前线程的名字。
- setName():设置当前线程的名字。
- yield():释放当前cpu的执行权。
- join():在线程a中调用线程b的join()方法,此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态。
- sleep(long millitime):让当前线程“睡眠”指定的millitime毫秒。在指定的millitime毫秒时间内,当前线程是阻塞状态。
- isAlive():判断当前线程是否存活。
- getPriority():获取线程的优先级。
- setPriority(int p):设置线程的优先级。
- 线程的优先级有以下三种,MAX_PRIORITY:10;MIN _PRIORITY:1;NORM_PRIORITY:5。
创建多线程的方式
继承Thread类
步骤:
- 创建一个继承于Thread类的子类;
- 重写Thread类中的run()方法,将次线程执行的操作声明在run()方法中。
- 创建Thread类的子类对象。
- 通过此对象调用start()。
举例:三个窗口进行卖票(存在线程安全问题)
class MThread extends Thread{
private static int tickets = 100;
@Override
public void run() {
while(true){
if(tickets > 0){
System.out.println(getName() + "卖票,票号为:" + tickets--);
}else{
break;
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
MThread t1 = new MThread ();
MThread t2 = new MThread ();
MThread t3 = new MThread ();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
说明:局限于类的单继承性。
实现Runnable接口
步骤:
- 创建一个实现Runnable接口的类。
- 实现类去实现Runnable中的抽象方法:run()。
- 创建实现类的对象。
- 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象。
- 通过Thread类的对象调用start()。
举例:三个窗口进行卖票(存在线程安全问题)
class MThread implements Runnable{
private int tickets = 100;
@Override
public void run() {
while(true){
if(tickets > 0){
System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + tickets--);
}else{
break;
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
MThread m = new MThread();
Thread t1 = new Thread(m);
Thread t2 = new Thread(m);
Thread t3 = new Thread(m);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
说明:不会局限于类的单继承性;适合处理多个线程共享数据的情况。
实现Callable接口
步骤:
- 创建一个实现Callable的实现类。
- 实现call方法,将此线程需要执行的操作声明在call()中。
- 创建Callable接口实现类的对象。
- 将此Callable接口实现类的对象作为参数传递到FutureTask构造器中,创建FutureTask的对象。
- 将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()。
举例:遍历100以内的偶数,并且计算他们的和
class MThread implements Callable{
@Override
public Object call() throws Exception {
int sum = 0;
for (int i = 2; i < 101; i+=2) {
System.out.println(i);
sum += i;
}
}
return sum;
}
}
public class ThreadTest {
public static void main(String[] args) {
MThread thread = new MThread ();
FutureTask futureTask = new FutureTask(thread);
new Thread(futureTask).start();
try {
//get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值。
Object sum = futureTask.get();
System.out.println("总和为:" + sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
说明:call()方法有返回值,并且可以抛出异常;callable支持泛型。
线程池
步骤:
- 提供指定线程数量的线程池。
- 执行指定的线程的操作。需要提供实现Runnable接口或Callable接口实现类的对象。
- 关闭线程池。
举例:两个线程遍历100以内的奇偶数
class NumberThread implements Runnable{
@Override
public void run() {
for(int i = 1;i < 101; i+=2){
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
class NumberThread1 implements Runnable{
@Override
public void run() {
for(int i = 2;i < 101; i+=2){
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
public class ThreadPool {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);
ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
service.execute(new NumberThread());//适用于Runnable
service.execute(new NumberThread1());//适用于Runnable
//service.submit(Callable callable);//使用于Callable
service.shutdown();
}
}
说明:提高了响应速度;降低资源消耗;便于线程管理。
线程同步机制
解决线程安全问题
同步代码块
synchronized(对象){//需要被同步的代码}
举例:三个窗口卖票
class Windows extends Thread{
private static int tickets = 100;
@Override
public void run() {
while(true){
synchronized(Windows.class){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(tickets > 0){
System.out.println(getName() + "卖票,票号为:" + tickets--);
}else{
break;
}
}
}
}
}
public class Test {
public static void main(String[] args) {
Windows t1 = new Windows();
Windows t2 = new Windows();
Windows t3 = new Windows();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
同步方法
将synchronized放到方法的声明中。
举例:三个窗口卖票。
class Windows implements Runnable {
private int tickets = 100;
@Override
public void run() {
while(true){
show();
}
}
private synchronized void show(){
if(tickets > 0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + tickets--);
}
}
}
public class Test{
public static void main(String[] args) {
Windows t = new Windows();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();t2.start();t3.start();
}
}
Lock
class A{
private final ReentrantLock lock = new ReentrantLock();
public void m(){
lock.lock();
try{
//保证线程安全的代码
}
finally{
lock.unlock();
}
}
}
举例:三个窗口卖票
class Window implements Runnable{
private int ticket = 100;
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while(true){
try{
lock.lock();
if(ticket > 0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket--);
}
}finally {
lock.unlock();
}
}
}
}
public class LockTest {
public static void main(String[] args) {
Window w = new Window();
Thread t1 = new Thread(w);
Thread t2 = new Thread(w);
Thread t3 = new Thread(w);
t1.setName("线程1");t2.setName("线程2");t3.setName("线程3");
t1.start();t2.start();t3.start();
}
}
synchronized和lock对比:
- lock是显示锁,手动开启和关闭;synchronized是隐式锁,出了作用域自动释放。
- lock只有代码块锁;synchronized有代码块锁和方法锁。
- 使用lock锁,JVM将花费较少的时间来调度线程,性能更好;并且具有更好的扩展性。
线程通信
三个方法
- wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
- )notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个。
- notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。
说明
- wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。
- wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。否则,会出现IllegalMonitorStateException异常。
- wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中。
举例:生产者消费者问题
class Clerk{
private int productCount = 0;
public synchronized void produceProduct(){
if(productCount < 20){
productCount ++;
System.out.println(Thread.currentThread().getName() + "生产第" + productCount + "个产品");
notify();
}else {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void consumeProduct() {
if(productCount > 0){
System.out.println(Thread.currentThread().getName() + "消费第" + productCount + "个产品");
productCount --;
notify();
}else {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Productor extends Thread{
private Clerk clerk;
public Productor(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
System.out.println("生产者" + Thread.currentThread().getName() + "开始生产");
while(true){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.produceProduct();
}
}
}
class Consumer extends Thread{
private Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
System.out.println("消费者" + Thread.currentThread().getName() + "取走产品");
while(true){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.consumeProduct();
}
}
}
public class ProductTest {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Productor p1 = new Productor(clerk);
p1.setName("生产者1");
Consumer c1 = new Consumer(clerk);
c1.setName("消费者1");
p1.start();c1.start();
}
}
最后
在文章的最后作者为大家整理了很多资料!包括java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书等等!
全部免费分享给大家,欢迎关注公众号:前程有光领取!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。