记录一次回客科技有关线程的笔试题,三个线程加法和一个线程减法 ,延申的两个线程交替执行

今天去了回客科技 笔试了一波。很遗憾啊,脑袋有思路 但是还没到手写代码很熟练的程度,基本功不到位。

第一道:线程的题:三个线程 +1 一个线程 -1 运算 。

看到网上还有四个线程的,两个加法计算,两个减法运算。基本的思路都是一样的 ,注意看同步处理。

下面贴出代码实现:

public class AddTest {

    private static int i;

    private static Object object = new Object();

    public static void main(String[] args) {

        new Thread(() -> {
            synchronized (object) {
                i++;
            }
        }).start();

        new Thread(() -> {
            synchronized (object) {
                i++;
            }

        }).start();

        new Thread(() -> {
            synchronized (object) {
                i++;
            }
        }).start();

        new Thread(() -> {
            synchronized (object) {
                i--;
            }
        }).start();//这里睡眠 等所有线程运行完毕 看最终的数值,2
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(i);

    }
}

 这里引申出来了其他问题的思考

第1种:synchronized void add  修饰普通方法 等同于
synchronized (this)
  public int i = 0;

    public void add(String threadName) {
        synchronized (this) {
            i++;
            System.out.println(threadName + "加法运算:" + i);
        }
    }

//上面代码等于如下代码:

   public synchronized void add(String threadName) {

            i++;
            System.out.println(threadName + "加法运算:" + i);

    }

  

第2种:synchronized static void add  修饰静态方法 等同于
synchronized (*.class)

说明:以上两种我分析为 synchornized 修饰普通方法和this 对应的是同一个实例对象。而修饰静态方法和class 是对应的同一个类的 唯一的class对象。这个是我的理解,有错误之处请各位指正。在此谢过

第二道:一个线程加一运算,一个线程做减法运算,多个线程同时交替运行(延申的)

第1种方法:使用Synchronized 实现
public class Count {
    private int num = 0;
    private boolean flag = false; // 标识

    //加法
    public synchronized void add() {
        while (flag) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.num++; //加
        System.out.println(Thread.currentThread().getName() + "........" + this.num);
        this.flag = true; //设置标识为true
        notifyAll(); //唤醒所有在线程池中冻结的线程,会把所有都唤醒

    }

    //减法
    public synchronized void sub() {
        while (!flag) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.num--; //减
        System.out.println(Thread.currentThread().getName() + "........" + this.num);
        this.flag = false; //设置标识为true
        notifyAll(); //唤醒所有在线程池中冻结的线程,会把所有都唤醒
    }
}

 第2种 :使用Lock 锁实现

public class CountLock {

    private int num = 0;
    private boolean flag = false; // 标识
    Lock lock = new ReentrantLock(); // 锁
    Condition add = lock.newCondition(); // 加法锁
    Condition sub = lock.newCondition();// 减法锁

    public void add() {
        lock.lock();// 锁上
        try {
            while (flag) {  //循环判断

                add.await();
            }
            this.num++;
            System.out.println(Thread.currentThread().getName() + "........" + this.num);
            this.flag = true; // 设置标识
            sub.signal(); // 唤醒指定线程
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void sub() {
        lock.lock();// 锁上
        try {
            while (!flag) {//循环判断
                sub.await();
            }
            this.num--;
            System.out.println(Thread.currentThread().getName() + "........" + this.num);
            this.flag = false; // 设置标识
            add.signal(); // 唤醒指定线程
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

  

调用的 main 方法:
    public static void main(String[] args) {
        //Count c=new Count();
        CountLock c=new CountLock();

        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    c.add();
                }
            }
        });
        Thread t2=new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    c.sub();
                }

            }
        });

        t1.start();
        t2.start();
   //这里感觉线程少可以再启动 两个t3或者t4 来验证真实性

    }

  

这里延申的知识点参考博客:

java synchronized修饰普通方法,修饰静态方法,修饰代码块,修饰线程run方法 比较





原文地址:https://www.cnblogs.com/liran123/p/9393153.html

时间: 2024-11-10 13:38:16

记录一次回客科技有关线程的笔试题,三个线程加法和一个线程减法 ,延申的两个线程交替执行的相关文章

回客科技 面试的 实现ioc 容器用到的技术,简述BeanFactory的实现原理,大搜车面试的 spring 怎么实现的依赖注入(DI)

前言:这几天的面试,感觉自己对spring 的整个掌握还是很薄弱.所以需要继续加强. 这里说明一下spring的这几个面试题,但是实际的感觉还是不对的,这种问题我认为需要真正读了spring的源码后说出来的东西才有意义.这种面试的问法,也只能是面试的问法,对实际的掌握还是没有丝毫意义的.所以我认为 有机会一定要读下spring的源码 来过一遍 具体实现,这样的才是有意义的做法.同意的请举手. 这里说明一下这三个spring 面试问题: 1.回客科技 面试的 实现ioc 容器用到的技术 第1种 说

线程基础知识系列(三)线程的同步

本文是系列的第三篇,前面2篇,主要是针对单个线程如何管理,启动等,没有过多涉及多个线程是如何协同工作的. 线程基础知识系列(二)线程的管理 :线程的状态,控制,休眠,Interrupt,yield等 线程基础知识系列(一)线程的创建和启动  :线程的创建和启动,join(),daemon线程,Callable任务. 本文的主要内容 何谓线程安全? 何谓共享可变变量? 认识synchronized关键字 认识Lock synchronized vs Lock 1.何谓线程安全 多线程是把双刃剑,带

JUC-Condition和Lock实践-线程按序交替执行

编写一个程序,开启 3 个线程,这三个线程的 ID 分别为 A.B.C,每个线程将自己的 ID 在屏幕上打印 10 遍,要求输出的结果必须按顺序显示.如:ABCABCABC-- 依次递归 这里只使用conditon和Lock组合使用,不考虑synchronized和wait的方式: 第一种方式:使用一个condition,跟while条件组合. 通过signalAll,每次执行完唤醒所有的线程. 每个线程唤醒后,是否阻塞通过while里面的变量值来决定: package com.atguigu.

Java笔试题-线程编程方面

Ja 线程编程方面 60.java中有几种方法可以实现一个线程?用什么关键字修饰同步方法?stop()和suspend()方法为何不推荐使用? 答:有两种实现方法,分别是继承Thread类与实现Runnable接口 用synchronized关键字修饰同步方法 反对使用stop(),是因为它不安全.它会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改它们.结果很难检查出真正的问题所在.suspend()方法容易发生死锁.调用suspend()的时候,

有意思的笔试题记录与分析

昨天参加了某公司的笔试,总的来说题目很简单.但是还是有几个个题目是很有意思的,拿来和大家分享下! 1.小周带着他的鸵鸟穿越1000公里的沙漠,运送3000颗白菜.已知鸵鸟一次性可驼1000颗白菜,但每走1公里又要吃掉1棵白菜,问:小周最终可以运多少颗白菜? 分析:记得以前算法设计书上有个类似的油车过沙漠的问题,当时这问题是用倒推法来解决的,因为它有个结题突破口:油车以最少的耗油量穿过沙漠.本题同是过沙漠问题,但是却没有像油车过沙漠的解题突破口,怎么办呢?我们先想一个极限:让小周直接带着1000颗

阿里笔试题记录(Android客户端部分)

阿里笔试题记录(Android客户端部分) 选择题 结果应该是选择 80,8 思路: - 指针的值都是一个个地址,而地址是用无符号整型值来表示的,也就是unsigned int.因此一个指针类型变量的大小就是unsigned int类型的大小. - 64位系统,一个地址占用的二进制位数为64(8字节),32位系统,地址的二进制位数32(4字节).参考64位操作系统的指针不都是64位吗 32位cpu和64位cpu,这个位数指的是数据字长,而不是地址字长.两者没有必然的数值上的联系.处理器字长是指处

线程的2种实现和线程的交替执行

学了线程,收获不少,记录下了吧. 一.线程的主要两种实现方法. 1.继承Thread类,重写run()方法 main方法中创建子类,引用调用start()方法 实例如下: //继承Thread类,重写run()方法 public class ThreadOne extends Thread { public void run() { for (int i = 1; i <=100; i++) { System.out.println(this.getName()+":"+i);

线程代替epll实现协程的原理(yield调用next时的函数使用其他线程进行处理,不影响主线程继续运行,next异步处理线程处理后使用send传回处理结果)

1 异步的实际说明 对于耗时的过程,我们将其交给别人(如其另外一个线程)去执行,而我们继续往下处理,当别人执行完耗时操作后再将结果反馈给我们,这就是我们所说的异步. 我们用容易理解的线程机制来实现异步. 2. 协程写法实现原理 在使用回调函数写异步程序时,需将本属于一个执行逻辑(处理请求a)的代码拆分成两个函数req_a和on_finish,这与同步程序的写法相差很大.而同步程序更便于理解业务逻辑,所以我们能否用同步代码的写法来编写异步程序? 回想yield关键字的作用? 初始版本 # codi

头条面试题之实现两个线程轮流打印字符串

在面试头条的时候,有一个很有意思的题目,利用两个线程交替打印一个字符串,这里主要就是对多线程中wait/notify的应用,特此记录. 对于wait()和notify()的理解,还是要从jdk官方文档中开始,在Object类方法中有: void notify() Wakes up a single thread that is waiting on this object’s monitor. 译:唤醒在此对象监视器上等待的单个线程 void notifyAll() Wakes up all t