黑马程序员---Java基础---多线程

时间:2023-02-20 10:45:47

-----------android培训java培训、java学习型技术博客、期待与您交流!------------ 


一、进程和线程的概述

1、进程:

进程:它是"操作系统"中的概念;对于操作系统来说,每个单独运行的"程序"就是一个"进程";

多进程:是指操作系统可以同时维护多个应用程序的同时运行;统一分配资源;

多进程的意义:

1).充分的利用系统资源;

2).可以提高用户的体验度;使用户有非常好的使用体验;

2、线程:

线程:线程是指,由一个"进程"中启动的一个可以独立运行的代码块;它是某个进程的一部分;

线程可以跟"主进程"一同抢夺系统资源;一个主进程可以开出任意多的线程;

多线程:是指一个程序可以开出多个"线程"同时执行;

多线程的意义:

1).充分的利用系统资源;

2).对于一个软件来说,就好像同时在有多个功能在一起运行;

3、多线程程序和单线程程序:

单线程程序:只有一条执行路径;后面的代码必须等待前面的代码执行完毕才能获得执行;

多线程程序:可以有多条执行路径,就好像多个功能在同时运行;

4、并行和并发:

并行:是指两个线程在"某个时间段内",同时在运行;

并发:是指多个线程在"某个时间点上",同时访问同一资源;


二、多线程的实现方式一

1、实现线程的方式一:Java中的线程,使用:Thread类表示;

1).自定义线程类,继承自Thread;

2).重写run();

3).启动线程:

1>.实例化自定义线程类对象;

2>.调用线程对象的start()方法启动线程;

注意:

1).对于同一个Thread(包括子类)对象,不能多次调用start()方法;

2).对于同一个Thread(包括子类)类,可以产生多个对象,每个对象都可以单独start(),成为一个独立的线程;

package cn.hebei.sjz_线程;

/*
* 1、自定义线程类,继承自Thread,2、重写run();
*/
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(this.getName() + " i=" + i);
}
}
}
package cn.hebei.sjz_线程;/* * 3.启动线程: * 实例化自定义线程类对象; * 调用线程对象的start()方法启动线程; */public class Demo {public static void main(String[] args) {// 方式1MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.start();// 启动线程t2.start();t3.start();for (int j = 0; j < 100; j++) {System.out.println(Thread.currentThread().getName() + "    j=" + j);}}}


2、取和设置线程对象名

Thread类的基本获取和设置方法

public final String getName():获取线程名

public final void setName(String name):设置线程名

public static Thread currentThread():获取任意方法所在的线程名称

package cn.hebei.sjz_线程;

/*
* 获取和设置线程名
*/
public class Demo {
public static void main(String[] args) {
// 方式1
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
t1.start();
t2.start();
t3.start();
t1.setName("xu");
t2.setName("zhao");
t3.setName("le");
for (int j = 0; j < 100; j++) {
System.out.println(Thread.currentThread().getName() + " j=" + j);
}
}
}


3、线程的优先级

1.Java中线程优先级的范围:1--10(从低到高);

2.设置优先级:

getPriority():获取优先级;

setPriority():设置优先级;(范围一定从1--10)

3.注意:我们不要依赖于"线程优先级"的技术,期望某个线程先执行完毕;因为它不保证线程优先级高的

就一定先执行完毕,这个要由"操作系统"来统一调度;"高优先级"的线程只代表:具有更多的机会

被操作系统执行而已,并不代表一定会先执行完毕;另外,如果线程中所做的事情比较简单,线程"优先级"

的效果会不明显;


三、线程控制

线程休眠

public static void sleep(long millis)

线程加入:调用此方法的线程,将会保证先执行完毕,其它线程才可以被执行;

public final void join()

线程礼让:使调用的线程退回到"就绪"状态,等待操作系统再次分配,很有可能被操作系统再次分配到执行权;

public static void yield()

后台线程:如果on为true,则表示为:守护线程

public final void setDaemon(boolean on)

中断线程

public final void stop():不建议使用

public void interrupt():前提条件:线程的内部,一定要处于以下三种阻塞状态时:

1.Object-->wait()

2.Thread-->sleep()

3.Thread-->yield()

当在外部调用线程的interrupt()方法时,将促使上述方法抛出异常;


四、线程的使用方式二

1.自定义类,实现:Runnable接口;

2.重写run()方法;

3.启动线程:

1).实例化自定义类对象;

2).实例化一个Thread对象,并将自定义对象传递给Thread的构造方法;

3).调用Thread对象的start()方法启动线程;

package cn.hebei.sjz_线程;

/*
* 线程的实现方式二
*/
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " i=" + i);
}
}
}
package cn.hebei.sjz_线程;/*  * 实现多线程的方式2 */public class Demo {public static void main(String[] args) {//方式2MyRunnable myRun = new MyRunnable();Thread t = new Thread(myRun);t.start();for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "     i= " + i);}}}


五、同步的语法:

1. 同步代码块

synchronized(被锁的对象){

//同步的代码

}

被锁的对象:表示如果当前线程访问"被锁对象"的synchronized的代码块时,其它线程不能访问此代码块,

另外,也不能访问"被锁对象"中的其它synchronized的代码块;

2.同步的好处:解决了多线程并发访问的问题,使多线程并发访问的共享数据能够保持一致性;

3.同步的弊端:使当前的对象的工作效率降低;因为要处理线程同步的问题;


六、线程组

Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。

默认情况下,所有的线程都属于主线程组。

1.线程组就是将一些线程统一分组管理;

2.分组后,可以对组内的所有线程做统一的操作:比如:停止线程;

3.线程组:使用:ThreadGroup

4.在Thread类中:

ThreadGroup getThreadGroup():获取线程所在的线程组;

5.一个线程,在默认情况下,都属于"main"线程组;

6.我们可以自行设定线程组:

1).实例化一个ThreadGroup对象;

2).使用Thread的构造方法,指定线程组和相应的线程

Thread(ThreadGroup group, Runnable target) 分配新的 Thread 对象。

7.统一停止线程组内的所有线程:

ThreadGroup-->interrupt():

package cn.hebei.sjz_线程组;

public class Demo {
public static void main(String[] args) {
// ********默认线程组****************
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();

System.out.println("t1的线程组:" + t1.getThreadGroup().getName());
System.out.println("t2的线程组:" + t2.getThreadGroup().getName());

// *********自定义线程组***************
ThreadGroup tg = new ThreadGroup("Java基础组");
Thread th1 = new Thread(tg, t1);
Thread th2 = new Thread(tg, t2);

th1.start();
th2.start();
System.out.println("th1所在的线程组:" + th1.getThreadGroup().getName());
System.out.println("th2所在的线程组:" + th2.getThreadGroup().getName());

System.out.println("主程序休息2秒钟......");
try {
Thread.sleep(1000 * 2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("主程序停掉线程组内的所有线程:");
tg.interrupt();

}
}


七、线程池

JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法

public static ExecutorService newCachedThreadPool():创建一个可根据需要创建新线程的线程池

public static ExecutorService newFixedThreadPool(int nThreads):创建一个可重用固定线程数的线程池

public static ExecutorService newSingleThreadExecutor():创建一个使用单个 worker 线程的 Executor,以*队列方式来运行该线程。(

返回值:ExecutorService--线程池

执行线程,并缓存线程对象:

 Future<?> submit(Runnable task)

<T> Future<T> submit(Callable<T> task)

package cn.hebei.sjz_线程池;

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

public class Demo {
public static void main(String[] args) {
MyThread t1 = new MyThread();
// 获取一个线程池
ExecutorService service = Executors.newFixedThreadPool(2);
service.submit(t1);
System.out.println("主线程休息2秒钟......");
try {
Thread.sleep(1000 * 2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程醒来,再次调用线程......");
service.submit(t1);
}
}


八、实现线程的方式三

1.实现:Callable接口;

2.重写call()方法

3.启动线程:

1).获取线程池;

2).调用线程池的submit()方法启动并缓存线程;

package cn.hebei.sjz_线程;

import java.util.concurrent.Callable;

public class MyCallable implements Callable {
@Override
public Object call() throws Exception {
for(int i = 0;i < 100 ; i++){
System.out.println("i = " + i);
}
return null;
}
}
package cn.hebei.sjz_线程;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/* * 实现线程的方式3 */public class Demo3 {public static void main(String[] args) {//1.获取线程池ExecutorService service = Executors.newFixedThreadPool(2);//2.调用线程池的submit()方法执行线程MyCallable myCall = new MyCallable();service.submit(myCall);for(int k = 0 ; k < 100 ; k++){System.out.println("k = " + k);}service.shutdown();}}

九、定时器

Java中的定时器:

1.可以在指定的时间,开始做某件事情;

2.可以从指定的时间开始,并且间隔多长时间,会重复的做某件事情;

实现定时器:

1.java.util.TimerTask(抽象类):定义执行的任务

1).自定义类,继承自TimerTask;

2).重写run()方法;(将要执行的任务定义在这里)

2.java.util.Timer(类):计时,并启动任务;

构造方法:

Timer();

成员方法:

public void schedule(TimerTask task, long delay):在指定的delay延迟之后,启动任务task;

public void schedule(TimerTask task,long delay,long period):在指定的延迟之后,启动任务,并间隔指定时间重复的执行任务;

package cn.hebei.sjz_定时器;

import java.util.Timer;
import java.util.TimerTask;

class MyTimerTask extends TimerTask {
private Timer timer;

public MyTimerTask(Timer t) {
this.timer = t;
}

@Override
public void run() {
System.out.println("duang......");
// this.timer.cancel();//如果重复执行,这里就不能取消了;
}
}

public class Demo1 {
public static void main(String[] args) {
Timer timer = new Timer();
System.out.println("3秒后,开始执行,之后每隔1秒重复执行一次......");
// timer.schedule(new MyTimerTask(timer), 1000 * 3);
timer.schedule(new MyTimerTask(timer), 1000 * 3, 1000);
}
}