我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java学习随记之多线程编程

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java学习随记之多线程编程

Process和Thread

程序是指令和数据的有序集合, 本身没有运行的含义,是一个静态的概念。

进程是执行程序的一次执行过程,他是一个动态的概念,是系统资源分配的单位

一个进程中可以包含若干个线程,线程是CPU调度和执行的单位

线程创建

三种创建方法

继承Thread类


//创建线程方法一:继承Thread类,重写run() 方法,调用start开启主线程
public class TestThread01 extends Thread{
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 2000; i++) {
            System.out.println("我在看代码-----" + i);
        }
    }
    public static void main(String[] args) {
        //main线程,主线程
        //创建一个线程对象
        TestThread01 testThread01 = new TestThread01();
        //调用start方法开启多线程,子线程调用run方法,主线程和子线程并行交替执行
        testThread01.start();
        //testThread01.run(); //主线程调用run方法,只有主线程一条执行路径

        for (int i = 0; i < 2000; i++) {
            System.out.println("Im" + i);
        }
    }
}

总结:注意,线程开启不一定立即执行,由CPU调度处理

  • 子类继承Thread类,具备多线程能力、
  • 启动线程:子类对象.start()
  • 不推荐使用:避免OOP单继承局限性

小练习


import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;

//练习Thread,实现多线程同步下载图片
public class TestThread02 extends Thread{
    private String url;
    private String name;

    public TestThread02(String url, String name) {
        this.url = url;
        this.name = name;
    }
    @Override
    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloadr(url, name);
        System.out.println("下载了:" + name);

    }

    public static void main(String[] args) {
        TestThread02 t1 = new TestThread02("/file/upload/202211/12/2225u1rbm5f.jpg?…3dlaXhpbl80NDE3NjM5Mw==,size_16,color_FFFFFF,t_70", "1.png");
        TestThread02 t2 = new TestThread02("/file/upload/202211/12/v54grbnrbo1.jpg", "2.png");
        TestThread02 t3 = new TestThread02("/file/upload/202211/12/2225u1rbm5f.jpg?…3dlaXhpbl80NDE3NjM5Mw==,size_16,color_FFFFFF,t_70", "3.png");

        t1.start();
        t2.start();
        t3.start();
    }
}
//下载器
class WebDownloader{
    public void downloadr(String url, String name){
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常, downloader出现问题");
        }
    }
}

实现Runnable


//创建线程方式二:实现Runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法
public class TestThread03 implements Runnable{
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 2000; i++) {
            System.out.println("我在看代码-----" + i);
        }
    }

    public static void main(String[] args) {
        //创建runnable 接口的实现类对象
        TestThread03 testThread03 = new TestThread03();

        //创建线程对象,通过线程对象来开启线程,代理
//        Thread thread = new Thread(testThread03);
//        thread.start();
        new Thread(testThread03).start();
        

        for (int i = 0; i < 1000; i++) {
            System.out.println("Im" + i);
        }
    }
}

总结:

  • 实现接口Runnable具备多线程能力
  • 启动线程:传入目标对象+Thread对象.start()
  • 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被线程使用

出现的问题

多个线程操作操作同一个资源的情况下,线程不安全,数据紊乱


//多个线程同时操作同一个对象
//买火车票的例子

//发现问题:多个线程操作操作同一个资源的情况下,线程不安全,数据紊乱
public class TestThread04 implements Runnable {

    //票数
    private int ticketNums = 10;

    @Override
    public void run() {
        while (true) {
            if (ticketNums <= 0) {
                break;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "拿到了第" + ticketNums-- + "票");
        }
    }

    public static void main(String[] args) {
        TestThread04 testThread04 = new TestThread04();

        new Thread(testThread04, "老师").start();
        new Thread(testThread04, "黄牛").start();
        new Thread(testThread04, "小明").start();
    }
}

实现Callable接口

1、实现Callable接口,需要返回值类型

2、重写call方法,需要抛出异常

3、创建目标对象

4、创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(3);(使用了线程池)

5、提交执行:Future r1 = ser.submit(t1);

6、获取结果:boolean res1 = r1.get();

7、关闭服务:ser.shutdown();


import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

//线程创建方式三:实现Callable接口(了解即可)
// 实现Callable接口
public class TestCallable implements Callable<Boolean> {

    private String url;
    private String name;

    public TestCallable(String url, String name) {
        this.url = url;
        this.name = name;
    }
    @Override
    public Boolean call() {
        WebDownloader1 webDownloader1 = new WebDownloader1();
        webDownloader1.downloadr(url, name);
        System.out.println("下载了:" + name);
        return true;

    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable t1 = new TestCallable("/file/upload/202211/12/2225u1rbm5f.jpg?…3dlaXhpbl80NDE3NjM5Mw==,size_16,color_FFFFFF,t_70", "1.png");
        TestCallable t2 = new TestCallable("/file/upload/202211/12/v54grbnrbo1.jpg", "2.png");
        TestCallable t3 = new TestCallable("/file/upload/202211/12/2225u1rbm5f.jpg?…3dlaXhpbl80NDE3NjM5Mw==,size_16,color_FFFFFF,t_70", "3.png");

        //1、创建执行服务()    线程池
        ExecutorService ser = Executors.newFixedThreadPool(3);
        //2、提交执行
        Future<Boolean> r1 = ser.submit(t1);
        Future<Boolean> r2 = ser.submit(t2);
        Future<Boolean> r3 = ser.submit(t3);

        //3、获取结果
        boolean res1 = r1.get();
        boolean res2 = r2.get();
        boolean res3 = r3.get();

        //4、关闭服务
        ser.shutdown();

    }

}
//下载器
class WebDownloader1{
    public void downloadr(String url, String name){
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常, downloader出现问题");
        }
    }
}

Lambda表达式

为什么要使用lamba表达式

避免匿名内部类定义过多

可以让代码看起来更整洁

去掉了一堆没有意义的代码,只留下核心逻辑

示例




public class TestLambda01 {

    //3、静态内部类
    static class Like2 implements ILike {

        @Override
        public void lambda() {
            System.out.println("I like lambda2");
        }
    }

    public static void main(String[] args) {
        ILike like = new Like();
        like.lambda();

        like = new Like2();
        like.lambda();

        //4、局部内部类
        class Like3 implements ILike {
            @Override
            public void lambda() {
                System.out.println("I like lambda3");
            }
        }
        like = new Like3();
        like.lambda();

        //5、匿名内部类
        like = new ILike() {
            @Override
            public void lambda() {
                System.out.println("I like lambda4");
            }
        };
        like.lambda();

        //6、用lambda简化 jdk1.8特性
        like = ()->{
            System.out.println("I like lambda5");
        };
        like.lambda();

    }
}

//1、定义一个函数式接口----必须有
interface ILike {
    void lambda();
}

//2、实现类
class Like implements ILike {

    @Override
    public void lambda() {
        System.out.println("I like lambda");
    }
}

对于lambda表达式的简化


public class TestLambda02 {

    public static void main(String[] args) {
        //标准格式
//        ILove love = (int a)->{
//                System.out.println("I Love you " + a);
//        };
        //简化1   去掉参数类型,多个不同类型的参数也可以直接去掉
        ILove love = (a) -> {
            System.out.println("I love you " + a);
        };
        //简化2   去掉括号    -->仅单参数
        love = a->{
            System.out.println("I love you " + a);
        };
        //简化3   去掉花括号  --> 仅lambda表达式有一行时才可
        love = a -> System.out.println("I love you " + a);
        love.love(520);
        //使用lambda表达式仅适用于函数式接口(接口里只有一个函数接口)
    }
}

interface ILove {
    void love(int a);
}

静态代理


//静态代理模式:
//真实对象和代理对象都要实现同一个接口
//代理对象要代理真实角色
//好处:
    //代理对象可以做很多真实对象做不了的事
    //真实对象专注做自己的事
public class StaticProxy {
    public static void main(String[] args) {
        You you = new You();

        new Thread(	() -> System.out.println("I Love You")).start();
        new WeddingCompany(new You()). HappyMarry();
        
        
    }
}

interface Marry {
    void HappyMarry();

}
// 真实对象
class You implements Marry {
    @Override
    public void HappyMarry() {
        System.out.println("Happy");
    }
}

// 代理
class WeddingCompany implements Marry {
    //代理谁->真实目标角色
    private Marry target;

    public WeddingCompany(Marry target) {
        this.target = target;
    }

    @Override
    public void HappyMarry() {
        before();
        this.target.HappyMarry();
        after();
    }

    private void after() {
        System.out.println("后");
    }

    private void before() {
        System.out.println("前");
    }
}

线程状态

方法 说明
setPriority(int newPriority) 更改线程的优先级
static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠
void join() 等待该线程终止
static void yield() 暂停当前正在执行的线程对象,并执行其他线程
void interrupt() 中断线程,别用这个方式
boolean isAlive() 测试线程是否处于某个活动状态

线程终止

  • 不推荐使用JDK提供的stop()、destroy()方法
  • 推荐线程自己停止下来
  • 建议使用一个标志位进行终止变量,当flag = false,则终止线程运行

//测试stop
//1、建议线程正常停止---->利用次数,不建议死循环
//2、建议使用标志位----->设置一个标志位
//3、不要使用stop或者destroy等过时或者jdk不推荐的方法
public class TestStop implements Runnable {
    //1、设置一个标志位
    private boolean flag = true;

    @Override
    public void run() {
        int i = 0;
        while (flag) {
            System.out.println("run-----thread" + i++);
        }
    }
    //2、设置一个公开的方法停止线程,转换标志位
    public void stop() {
        this.flag = false;
    }
    public static void main(String[] args) throws InterruptedException {
        TestStop testStop = new TestStop();

        new Thread(testStop).start();

        for (int i = 0; i < 1000; i++) {
            Thread.sleep(1);
            if (i == 900) {
                testStop.stop();

                System.out.println("Stop");
                break;
            }
        }
    }
}

线程休眠

  • sleep(时间) 指定当前线程阻塞的毫秒数
  • sleep存在异常InterruptedException
  • sleep时间达到后进入就绪状态
  • sleep可以模拟网络延时(放大问题的发生性),倒计时等
  • 每一个对象都有一个锁,sleep不会释放锁

import java.text.SimpleDateFormat;
import java.util.Date;

public class TestSleep2 {
    //模拟倒计时
    public static void tenDown(){
        int num = 10;
        while (num > 0) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(num--);
        }
    }

    public static void main(String[] args) {
        //打印当前时间
        Date startTime = new Date(System.currentTimeMillis());  //获取时间

        while (true) {
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:MM:SS").format(startTime));
                startTime = new Date(System.currentTimeMillis());//更新时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

线程礼让

  • 礼让线程,让当前正在执行的线程停止,但不阻塞
  • 让线程从运行态转换为就绪态
  • 让CPU重新进行调度,礼让不一定成功,看CPU心情

public class TestYield {
    public static void main(String[] args) {
        Myyield myyield = new Myyield();

        new Thread(myyield, "A").start();
        new Thread(myyield, "B").start();
    }
}

class Myyield implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() +  "线程开始");
        Thread.yield();
        System.out.println(Thread.currentThread().getName() +  "线程停止");
    }
}

JOIN

JOIN合并线程,待此线程执行完后,再执行其他线程,其他线程阻塞

可以想象成插队


//插队
public class TestJoin implements Runnable{
    @Override
    public void run() {
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 100; i++) {
            System.out.println("VIP" + i);
        }
    }

    public static void main(String[] args) {
        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin);
        thread.start();

        for (int i = 0; i < 1000; i++) {
            if (i == 200) {
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("main" + i);
        }
    }
}

线程状态观测

线程状态。线程可以处于以下状态之一:

NEW

尚未启动的线程处于此状态。

RUNNABLE

在Java虚拟机中执行的线程处于此状态。

BLOCKED

被阻塞等待监视器锁定的线程处于此状态。

WAITING

无限期等待另一个线程执行特定操作的线程处于此状态。

TIMED_WAITING

正在等待另一个线程执行最多指定等待时间的操作的线程处于此状态。

TERMINATED

已退出的线程处于此状态。


//观测测试线程的状态
public class TestStatus {

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(i);
            }
            System.out.println("/////////////");
        });

        //观察状态
        Thread.State state = thread.getState();
        System.out.println(state);

        //观察启动后
        thread.start();

        state = thread.getState();
        System.out.println(state);

        while (state != Thread.State.TERMINATED) { //只要线程不终止,就一直输出状态
            try {
                Thread.sleep(100);
                state = thread.getState();
                System.out.println(state);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }


    }
}

线程的优先级

Java提供一个线程调度器来监控程序中启动后进入就绪态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行

线程的优先级用数字表示,范围从1~10

  • Thread.MIN_PRIORITY = 1;
  • Thread.MAX_PRIORITY = 10;
  • Thread.NORM_PRIORITY = 5;

使用以下方法改变或者获取优先级

  • getPriority
  • setPriority

优先级低只是意味着获得调度的概率低,并不是优先级低的就不会调用了,这都是看CPU的调度


public class TestPriority extends Thread {

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + "====>" + Thread.currentThread().getPriority());

        MyPriority myPriority = new MyPriority();

        Thread t1 = new Thread(myPriority);
        Thread t2 = new Thread(myPriority);
        Thread t3 = new Thread(myPriority);
        Thread t4 = new Thread(myPriority);
        Thread t5 = new Thread(myPriority);

        t1.start();
        t2.setPriority(1);
        t2.start();
        t3.setPriority(4);
        t3.start();
        t4.setPriority(Thread.MAX_PRIORITY);
        t4.start();
        t5.setPriority(8);
        t5.start();
    }
}

class MyPriority implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "====>" + Thread.currentThread().getPriority());
    }
}

守护(daemon)线程

  • 线程分为用户线程和守护线程
  • JVM虚拟机必须确保用户线程执行完毕
  • JVM虚拟机不用等待守护线程执行完毕

public class TestDaemon {
    public static void main(String[] args) {
        God god = new God();
        You you = new You();

        Thread thread = new Thread(god);
        thread.setDaemon(true);//默认式false表示是用户线程,正常的线程是用户线程

        thread.start();

        new Thread(you).start();
    }

}

//上帝
class God implements Runnable {

    @Override
    public void run() {
        while (true) {
            System.out.println("god");
        }
    }
}
//你
class You implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("Happy");
        }
        System.out.println("Goodbye world");
    }
}

同步(synchronized)

synchronized

由于我们可以提出private关键字来保证数据对象只能被方法访问,所以我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:synchronized方法和synchronized块。


public synchronized void method(){}

synchronized方法控制对“对象”的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行

缺陷:若将一个大的方法声明为synchronized,将会影响效率

同步方法

synchronized方法控制对成员变量或者类属性对象的访问,每个对象对应一把锁。写法如下:


public synchronized void test(){
    //。。。。
}
  1. 如果修饰的是具体对象:锁的是对象
  2. 如果修饰的是成员方法:锁的是this
  3. 如果修饰的是静态方法:锁的就是这个对象.class

每个synchronized方法都必须获得该方法的对象的锁才能执行,否则所属的这个线程阻塞,方法一旦执行,就独占该锁,直到该方法返回时,锁释放。

原程序:


public class Checkout {

    public static void main(String[] args) {
        Account account = new Account(200000, "礼金");
        Drawing you = new Drawing(account, 80000, "你");
        Drawing wife = new Drawing(account, 140000, "your wife");
        you.start();
        wife.start();
    }
}

class Account {
    int money;
    String name;

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}

class Drawing extends Thread {
    Account account;
    int outMoney;
    int outTotal;

    public Drawing(Account account, int outMoney, String name) {
        super(name);
        this.account = account;
        this.outMoney = outMoney;
    }

    @Override
    public void run() {
        test();
    }

    public void test() {
        if (account.money < outMoney) {
            System.out.println("余额不足");
            return;
        }
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        account.money -= outMoney;
        outTotal += outMoney;
        System.out.println(this.getName() + "-----账户余额为:" + account.money);
        System.out.println(this.getName() + "-----总共取到了:" + outTotal);
    }
}

显然,上面的代码会出现负数,但是我们不希望它出现负数。

同步方法的写法代码,以上面代码为例,直接在提款机的操作,把run方法或者里面的内容提出来变成test,加上synchronized修饰:


@Override
public void run(){
}
public synchronized void test(){
}

但是这样仍会发现出现负数,锁定失败。

分析:

我们认为在test方法里进行的对象修改,所以把他锁上就好了,但是,对于这个类,这个提款机来说,test时成员方法,因此锁的对象实际上是this,也就是提款机(Drawing)。

但是我们的初衷,希望线程锁定的资源是Account对象,而不是提款机对象。

同步块

除了方法,synchronized还可以修饰块,叫做同步块。

synchronized修饰同步块的方式是:

synchonized (obj){ }

其中的obj可以是任何对象,但是用到它,肯定是设置为那个共享资源,这个obj被称为同步监视器。同步监视器的作用就是,判断这个监视器是否被锁定(是否能访问),从而决定其是否能执行其中的代码。

Java的花括号中内容有一下几种:

  1. 方法里面的块:局部快。解决变量作用域的问题,快速释放内存(比如方法里面再有个for循环,里面的变量)
  2. 类层的块:构造块。初始化信息,和构造方法是一样的
  3. 类层的静态块:静态构造块。最早加载,不是对象的信息,而是类的信息;
  4. 方法里面的同步块:监视对象。

第四种就是我们目前学习的同步块。

注意:如果是同步方法里,没必要指定同步监视器,因为同步方法的监视器已经是this或者.class

使用同步块对提款机问题进行修改:


public void test(){
    synchronized(account){
        
    }
}

也就是加上对account的监视器,锁住了这个对象 ,这样运行结果就正确了。

这种做法的效率不高,因为虽然对account上了锁,但是每一次都要把整个流程走一遍,方法体内的内容是很多的,另外,每次加锁与否,都是对性能的消耗,进入之后再出来,哪怕什么都不做,也是消耗。

其实,我们可以在加锁的外面再加一重判断,那么之后就没有必要再进行锁的过程了。


public void test(){
    if (account.money == 0){
        return;
    }
    synchronized(account){
    }
}

就是这样的代码,在并发量很高的时候,往往可以大大提高效率。

问题

synchronized块太小,可能锁不住,安全性又太低了,锁的方法太大,又会降低效率,所以要很注意控制范围 

以上就是Java学习随记之多线程编程的详细内容,更多关于Java多线程的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java学习随记之多线程编程

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java多线程之锁的强化学习

Java多线程的锁都是基于对象的,Java中的每一个对象都可以作为一个锁。这篇文章主要来通过一下示例为大家强化一下锁的相关知识的掌握,希望对大家有所帮助
2023-02-26

Java多线程之锁学习(增强版)

这篇文章主要为大家详细介绍了Java多线程中锁的相关知识,文中的示例代码讲解详细,对我们了解线程有一定帮助,需要的可以参考一下
2023-02-26

Python学习记录-多进程和多线程

[TOC]1. 进程和线程进程狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。广义定义:进程是一个具有一定独立功能的程序关于某个数据集
2023-01-31

Python 爬虫学习笔记之多线程爬虫

XPath 的安装以及使用 1 . XPath 的介绍 刚学过正则表达式,用的正顺手,现在就把正则表达式替换掉,使用 XPath,有人表示这太坑爹了,早知道刚上来就学习 XPath 多省事 啊。其实我个人认为学习一下正则表达式是大有益处的,
2022-06-04

java多线程编程之InheritableThreadLocal

InheritableThreadLocal的作用: 当我们需要在子线程中使用父线程中的值得时候我们就可以像使用ThreadLocal那样来使用InheritableThreadLocal了。 首先我们来看一下InheritableThre
2023-05-31

NodeJS学习笔记之网络编程

Node提供丰富的网络编程模块Node模块协议netTCPdgramUDPhttpHTTPhttpsHTTPSTCP服务事件分为下面两类 (1)、服务器事件 对于通过net.createServer()创建的服务器而言,它是一个EventE
2022-06-04

Java多线程Thread基础学习

每一个正在执行的程序都是一个进程,资源只有一块,所以在同一时间段会有多个程序同时执行,但是在一个时间点上,只能由一个程序执行,多线程是在一个进程的基础之上的进一步划分,需要的朋友可以参考下
2023-05-17

Java 多线程学习总结3

在上一篇中,我们当然希望a++,b++执行完之后,show方法再来show.我们需要的是“原子”动作,一次性地把a++,b++不间断地执行。在java中是利用“互斥”的方法,互斥谁呢?互斥的是相同对象的加锁代码。如果我们把第一篇的SomeB
2023-01-31

Java线程学习之并发编程知识点有哪些

本文小编为大家详细介绍“Java线程学习之并发编程知识点有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java线程学习之并发编程知识点有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。一、JMM 基础-
2023-07-02

python多线程学习

python多线程学习:python中的线程使用的两种方式:函数或者用类来包装线程对象。1、函数式:调用thread模块中start_new_thread()函数来产生新线程。#!/usr/bin/env python#coding:utf
2023-01-31

理解Java多线程之并发编程

这篇文章主要介绍了理解Java多线程之并发编程的相关资料,需要的朋友可以参考下
2023-02-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录