Java学习_20220626
多线程详解
Process和Thread
进程是执行程序的一次执行过程,是系统资源分配的单位。一个线程包括若干个线程(CPU调度和执行的单位)
程序(静态)-->进程-->线程(如main函数(用户线程)和gc函数(守护线程))
1.Thread方法
创建方式:继承Thread类,重写run()方法,调用start方法。
public class Thread_test extends Thread {
@Override
public void run() {
for (int i = 0; i < 30; i++) {
System.out.println("我在读书==="+i);
}
}
public static void main(String[] args) {
Thread_test thread_test = new Thread_test();
//thread_test.run();//先调用run方法里面的方法体
thread_test.start();//交叉执行,并行
for (int i = 0; i < 30; i++) {
System.out.println("今天是个好天气==="+i);
}
}
}
总结:注意,线程开启不一定立即执行,由cpu调度执行。
2. Runnable
实现Runnable接口,实现run()方法,编写线程执行体,创建线程对象,丢人runnable接口实现类,调用start()方法
public class Runnable_test implements Runnable{
@Override
public void run() { //run方法线程体
for (int i = 0; i < 20; i++) {
System.out.println("我再执行线程==="+i);
}
}
public static void main(String[] args) {
Runnable_test runnable_test = new Runnable_test();
//创建线程对象,通过线程对象来开启线程,代理的方式
new Thread(runnable_test).start();
for (int i = 0; i < 50; i++) {
System.out.println("-----for------"+i);
}
}
}
Thread也实现了Runnable接口 ,Java单继承,推荐使用Runnable接口,方便同一个对象被多个线程使用。
多个线程操作同一个资源的情况下,线程不安全,数据紊乱
3. Callable接口
(1)实现Callable接口,需要返回值类型,
(2)重写call方法,需要抛出异常,
(3)创建目标对象
(4)创建执行服务:ExecutorService ser = ExecutorService .newFixedThreadPool(1);
(5)提交执行:Future<Boolean> result1 = ser.submit(t1);
(6)获取结果:boolean r1 =result1.get();
(7)关闭服务:ser.shutdownNow();
public class TestCallable implements Callable<Boolean>{
@Override
public Boolean call() {}
}
Callable 的好处:1.可以定义返回值,2.可以抛出异常。
4.静态代理模式
真实对象(目标对象)和代理对象都要实现同一个接口;
代理对象要代理真实角色(传入真实对象)
好处:
代理对象可以做很多真实对象做不了的事情。
真实对象只专注做自己的事情。
5.Lambda表达式
函数式接口:接口中只包含唯一一个抽象方法,可通过Lambda表达式来创建该接口的对象。(如Runnable中只有一个run抽象方法)
public class TestLambda1 { //实现接口的方式,较为复杂
public static void main(String[] args) {
Ilove ilove = new Mylove();//接口new实现类
ilove.love("z"); //I love -> z
}
}
interface Ilove{
void love(String s);
}
class Mylove implements Ilove{
@Override
public void love(String s) {
System.out.println("I love -> "+s);
}
}
public class TestLambda1 {
//静态内部类
static class Youlove implements Ilove{
@Override
public void love(String s) {
System.out.println("You love -> "+s);
}
}
public static void main(String[] args) {
Ilove youlove = new Youlove();
youlove.love("A"); //You love -> A
}
}
interface Ilove{//定义一个函数式接口
void love(String s);
}
public class TestLambda1 {
public static void main(String[] args) {
//成员内部类
class Shelove implements Ilove{
@Override
public void love(String s) {
System.out.println("She love -> "+s);
}
}
Shelove shelove = new Shelove();
shelove.love("B"); //She love -> B
}
}
interface Ilove{//定义一个函数式接口
void love(String s);
}
public class TestLambda1 {
public static void main(String[] args) {
//匿名内部类
Ilove helove = new Ilove() {
@Override
public void love(String s) {
System.out.println("He LOVE -> "+s);
}
};
helove.love("C"); //He LOVE -> C
}
}
interface Ilove{//定义一个函数式接口
void love(String s);
}
//Lambda表达式
Ilove itlove =s -> System.out.println("it LOVE -> " + s);
itlove.love("D");
//总结:
/*
lambda表达式只能有一行代码的情况下才能简化为一行,两行及以上的情况用代码块{}包裹。
使用前提接口必须为函数式接口(只有一个抽象方法)
多个参数也可以同时去掉参数类型,但必须加上括号
*/
6.线程状态


(1)线程停止
建议线程正常停止——>利用次数,不建议死循环;
建议使用标志位——>设置一个标志位;
不要使用stop或者destroy等过时或者JDK不建议使用的方法
public class ThreadStop_test implements Runnable{
private boolean flag = true;//设置一个标志位
@Override
public void run() {
int i = 0;
while (flag){
System.out.println("run.....Thread "+i++);
}
}
public void stop(){ //设置一个公开的方法停止线程,转换标志位
this.flag = false;
}
public static void main(String[] args) {
ThreadStop_test threadStop_test = new ThreadStop_test();
new Thread(threadStop_test).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main"+i);
if(i == 900){
threadStop_test.stop(); //调用stop方法,让线程停止
System.out.println("线程该停止了");
}
}
}
}
(2)线程休眠
模拟网络延时:放大问题的发生性。(网络购票)
模拟倒计时
public class ThreadSleep_test {
public static void main(String[] args) throws InterruptedException {
new ThreadSleep_test().Down();
}
public void Down() throws InterruptedException {
int num = 10;
while(true){
Thread.sleep(1000);
System.out.println(num--);
if(num<=0){
break;
}
}
}
}
打印当前时间
public static void main(String[] args) {
//打印当前系统时间
Date startDate = new Date(System.currentTimeMillis());//获取系统当前时间
while (true){
try {
Thread.sleep(1000);
//在循环体中重新获取一遍,可得到最新值
startDate = new Date(System.currentTimeMillis());
System.out.println(new SimpleDateFormat("HH:mm:ss").format(startDate));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
(3)线程礼让
礼让线程,让当前正在执行的线程暂停,但不阻塞。将线程从运行状态转为就绪状态,该线程将再次和其他线程一起争取CPU资源,让cpu调度,所以礼让不一定成功。
Thread.yield();
获取当前线程的名字:Thread.currentThread().getName();
(4)合并线程Join(插队)
public class ThreadJoin_test implements Runnable{
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 1; i <= 100; i++) {
System.out.println("线程在执行。。。"+i);
}
}
public static void main(String[] args) throws InterruptedException {
ThreadJoin_test threadJoin_test = new ThreadJoin_test();
Thread thread = new Thread(threadJoin_test);
thread.start();
for (int i = 1; i <= 500; i++) {
if(i==10){
thread.join();//在主线程执行的过程中加入run方法中的方法体
}
System.out.println(Thread.currentThread().getName()+i);
}
}
}
(5)线程状态
thread.getState();
if ( state == Thread.State.TERMINATED ) // 判断线程是否终止
线程进入死亡状态,就不能再次启动。
(6)线程优先级
获取优先级:getPriority()
设置优先级:setPriority(int xxx)
(7)守护进程(daemon )
线程分为用户线程和守护线程、虚拟机必须确保用户线程执行完毕,但不用等待守护线程执行完毕。
线程变成守护线程:thread.setDaemon(true);//默认是false,表示用户线程,正常的线程都是用户线程。
浙公网安备 33010602011771号