Java两个线程配合输出1A2B3C4D...

Java实现DbSchema注册机:软件授权机制与逆向工程原理详解 软件授权机制是保护知识产权和确保软件商业价值的关键技术,其核心原理通常涉及加密算法、本地验证逻辑和状态持久化。在技术实现层面,常见的离线验证模式通过内置算法对用户输入进行变换和比对,其中哈希计算、字符串操作和代码混淆是提高安全性的常用手段。从工程实践角度看,理解这些机制不仅有助于进行软件安全研究,还能为设计健壮的授权系统提供参考。本文以教育研究为目的,通过模拟DbSchema的注册机实现,深入探讨了MD5哈希、字符串处理等基础技术,并结合逆向工程中常见的代码混淆和算法隐匿性挑战,展示了如何构建一个完整的授权 阅读详情

问题:Java两个线程,一个输出字母,另一个输出数字,如何能得到1A2B3C4D…(除文中提到的方法肯定还有其它方法)

方法一:LockSupport
public class TestThread {
    private static char[] data1 = {'1','2','3','4','5','6','7'};
    private static char[] data2 = {'a','b','c','d','e','f','g'};
    private static Thread t1,t2;
    public static void main(String[] args) {
        t1 = new Thread(
                ()->{
                    for(char temp : data1){
                        System.out.println(temp);
                        LockSupport.unpark(t2);//唤醒t2
                        LockSupport.park();//挂起当前线程
                    }
                }
        );
        t2 = new Thread(
                ()->{
                    for(char temp : data2){
                        LockSupport.unpark(t1);//唤醒t1
                        System.out.println(temp);
                        LockSupport.park()//挂起当前线程
                    }
                }
        );
        t1.start();
        t2.start();
    }
}
方法二:volatile + 自旋等待
public class TestThread {
    private static char[] data1 = {'1','2','3','4','5','6','7'};
    private static char[] data2 = {'a','b','c','d','e','f','g'};
    private static Thread t1,t2;
    private static volatile int currentThreadId = 1;

    public static void main(String[] args) {
        t1 = new Thread(
                ()->{
                    for(char temp : data1){
                        while(currentThreadId != 1) {
                        //忙等待
                        }
                        System.out.println(temp);
                        currentThreadId = 2;
                    }
                }
        );
        t2 = new Thread(
                ()->{
                    for(char temp : data2){
                        while(currentThreadId != 2){
                        //忙等待
                        }
                        System.out.println(temp);
                        currentThreadId = 1;
                    }
                }
        );
        t1.start();
        t2.start();
    }
}
方法三:原子类型 + 自旋等待
public class TestThread {
    private static char[] data1 = {'1','2','3','4','5','6','7'};
    private static char[] data2 = {'a','b','c','d','e','f','g'};
    private static Thread t1,t2;
    private static AtomicInteger currentThreadId = new AtomicInteger(1);

    public static void main(String[] args) {
        t1 = new Thread(
                ()->{
                    for(char temp : data1){
                        while(currentThreadId.get() != 1) {
                            //忙等待
                        }
                        System.out.println(temp);
                        currentThreadId.set(2);
                    }
                }
        );
        t2 = new Thread(
                ()->{
                    for(char temp : data2){
                        while(currentThreadId.get() != 2){
                            //忙等待
                        }
                        System.out.println(temp);
                        currentThreadId.set(1);
                    }
                }
        );
        t1.start();
        t2.start();
    }
}
方法四:阻塞队列
public class TestThread {
    private static char[] data1 = {'1','2','3','4','5','6','7'};
    private static char[] data2 = {'a','b','c','d','e','f','g'};
    private static Thread t1,t2;
    static BlockingQueue<String> q1 = new ArrayBlockingQueue<>(1);
    static BlockingQueue<String> q2 = new ArrayBlockingQueue<>(1);

    public static void main(String[] args) {
        t1 = new Thread(
                ()->{
                    for(char temp : data1){
                        System.out.println(temp);
                        try {
                            q1.put("t1打印成功");//t2线程满足执行条件
                            q2.take();//如果没内容就阻塞
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
        );
        t2 = new Thread(
                ()->{
                    for(char temp : data2){

                        try {
                            q1.take();//如果没内容就阻塞
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(temp);
                        try {
                            q2.put("t2打印成功");//t1线程满足执行条件
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
        );
        t1.start();
        t2.start();
    }
}
方法五:synchronized + wait()/notify()

注:可以使用CountDownLatch或者volatile修饰的变量等多种办法来保证t1先运行

public class TestThread {
    private static char[] data1 = {'1','2','3','4','5','6','7'};
    private static char[] data2 = {'a','b','c','d','e','f','g'};
    private static Thread t1,t2;
    private static Object lock = new Object();

    public static void main(String[] args) {
        t1 = new Thread(
                ()->{
                    synchronized (lock) {
                        for (char temp : data1) {
                            System.out.println(temp);
                                lock.notify();//随机唤醒一个在lock上等待的线程
                            try {
                                lock.wait();//使当前线程等待,并释放锁
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        lock.notify();//必须有,否则程序无法停止
                    }
                }
        );
        t2 = new Thread(
                ()->{
                    synchronized (lock) {
                        for(char temp : data2){
                            System.out.println(temp);
                            lock.notify();//随机唤醒一个在lock上等待的线程
                            try {
                                lock.wait();//使当前线程等待,并释放锁
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        lock.notify();//必须有,否则程序无法停止
                    }
                }
        );
        t1.start();
        t2.start();

    }
}
方法六:Lock + Condition

注:可以使用CountDownLatch或者volatile修饰的变量等多种办法来保证t1先运行

public class TestThread {
    private static char[] data1 = {'1','2','3','4','5','6','7'};
    private static char[] data2 = {'a','b','c','d','e','f','g'};
    private static Thread t1,t2;

    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        Condition condition1 = lock.newCondition();
        Condition condition2 = lock.newCondition();

        t1 = new Thread(
                ()->{
                    try{
                        lock.lock();
                        for (char temp : data1) {
                            System.out.println(temp);
                            condition2.signal();
                            condition1.await();
                        }
                        condition2.signal();//不加程序可能不会停止
                    }catch (Exception e){

                    }finally {
                        lock.unlock();
                    }
                }
        );
        t2 = new Thread(
                ()->{
                    try{
                        lock.lock();
                        for (char temp : data2) {
                            System.out.println(temp);
                            condition1.signal();
                            condition2.await();
                        }
                        condition1.signal();//不加程序可能不会停止
                    }catch (Exception e){

                    }finally {
                        lock.unlock();
                    }
                }
        );
        t1.start();
        t2.start();

    }
}
JMeter随机变量配置详解:从参数化到性能测试实战 在软件性能测试中,参数化是模拟真实用户行为、避免服务器缓存和防刷机制干扰的关键技术。其核心原理在于用动态数据替换脚本中的固定值,从而让测试请求具备多样性和随机性。这项技术的工程价值在于能显著提升测试结果的真实性和可信度,广泛应用于登录、搜索、下单等需要模拟不同用户或不同操作场景的压测任务。JMeter作为主流的性能测试工具,提供了RandomVariable配置元件来实现参数化,它支持定义数字范围、输出格式(如补零、UUID)、随机种子等高级功能,并能通过“每个线程独立种子”选项确保高并发下的数据随机性。本 阅读详情

相关推荐

O(1)恒定状态内存:稀疏写入场景下的确定性内存管理新范式

在实时系统与边缘计算中,'稀疏写入'(如IoT传感器更新、用户状态微调)常导致传统内存管理性能骤降——缓存污染、TLB刷新、GC扫描等隐性开销随数据规模增长而放大。O(1)恒定状态内存并非追求绝对内存占用不变,而是通过分离基态快照与增量投影,使元数据规模、访问跳转次数、缓存行影响及TLB压力四项核心状态指标保持常量级稳定。其技术价值在于为高频小更新、低延迟中间件和资源受限嵌入式设备提供可预测的内存行为。AURA-Mem正是这一范式的工程落地实现,已在物流调度、风控引擎等真实高并发服务中验证毫秒级写入稳定性与

weixin_33700350的博客 420

Java基础学习3(接口与画图板的实现)

接口与画图板的实现前言接口事件与监听接口格式及使用方法简单实现按钮的监听画图板的实现工具实现扩展一下 前言 接口是前天学习的, 但一直拖到今天才写,在构想思路的时候总感觉遗漏了什么,当时还是有不少启发的,但现在有的记不起来了(哎,记忆最好的时候还属高中啊),没办法,只能尽我所能了写了,以后学习到一个新的知识点之后,一定要当天或者第二天把它写出来,不要让它在你脑子过两夜。。。 接口 接口听起来挺熟悉的,我们电脑就有很多接口,那么java中的接口有什么用呢,既然都叫接口,肯定有异曲同工之处,电脑的接口外接很多设

leyuluzhou的博客 484

Spark环境搭建避坑指南:JDK/Scala/Hadoop版本精准匹配

Apache Spark并非即装即用的单机工具,而是一个深度耦合JVM生态的分布式计算引擎。其稳定运行依赖于JDK版本兼容性、Scala运行时一致性、Hadoop二进制ABI匹配及本地资源精准配置等底层原理。技术价值在于规避NoClassDefFoundError、线程创建失败、文件系统不支持等高频故障,保障ETL调试、SQL开发与实时流任务的可复现性。典型应用场景包括金融风控离线分析、电商推荐特征工程及IoT时序数据本地验证。本文聚焦Spark环境搭建这一基础但极易出错的关键环节,深入解析JDK版本匹配与

weixin_30256901的博客 389

多线程打印1-26以及A-Z

打印呈现效果是: 1A2B.........26Z 这里使用两种方法实现结果: 1、使用同步对象即锁对象 package Chapter08.HomeWork2; public class Alter { public static void main(String[] args) { Object lock = new Object(); Thread number = new Thread(new Runnable() {

weixin_52688663的博客 480

从零开始:HLW8110电能计量IC的硬件设计与软件调试全攻略

本文详细介绍了HLW8110电能计量IC的硬件设计与软件调试全流程,涵盖核心特性、抗干扰设计、UART通信协议及校准方法。通过实战案例和优化技巧,帮助工程师快速掌握高精度交流测量技术,适用于智能插座、充电桩等应用场景。

p5l2m9n4o6q的博客 576

sysrepo 开发者指南(一个基于libyang与支持rpc的数据库)

sysrepo 开发者指南(一个基于libyang与支持rpc的数据库) 日志记录 默认情况下,所有 Sysrepo 日志记录都处于关闭状态。如果启用,日志消息有 3 种输出。它们可以写入stderr、由 处理syslog或简单地传递给回调。 请务必注意,启用 Sysrepo 日志记录也会修改libyang日志记录设置。错误消息被视为标准 Sysrepo 错误,其他严重性较低的消息完全隐藏。要更改此行为,只需在启用 Sysrepo 日志记录后调整libyang日志记录设置。 此外,几乎每个 Sysrepo

weixin_43489394的博客 9227

java多线程--给点1,2,A,B四个线程,交叉输出数字和字母

输出例子:1A2B,1B2A,2B1A,2A1B,A1B2等 package observer; public class threadtest { private static boolean flag1,flag2,flagA,flagB;//判断哪个字符用过 private static int state = 1; //1是数字,2是字母 private

u010535345的博客 948

【亲测有效】OpenClaw Gateway 出现 “(no output)“ 卡死问题完整解决指南:从手动重启到 systemd Watchdog 自动恢复

最近在使用 OpenClaw(自托管 AI 助手框架,前身 Clawdbot/Moltbot)时,遇到了一个非常常见的顽疾:TUI(终端界面)或 Telegram 等通道经常显示 "(no output)",消息发出去后机器人完全没反应,看起来像是卡死了。

hampeter的博客 8609

【Java中编写程序,实现三个线程,运行输出 A1 B2 C3 A4 B5 C6 …..】

【代码】【Java中编写程序,实现三个线程,运行输出 A1 B2 C3 A4 B5 C6 …..】

相关项目可以查看https://gitee.com/fan-pl或https://github.com/fpl1116 330

HBuilderX结合Android Studio实现Uniapp安卓Apk高效离线打包指南

本文提供了一份详细的Uniapp安卓Apk离线打包实战指南。通过整合HBuilderX与Android Studio,手把手教你搭建本地编译环境、配置原生工程、执行核心打包流程,并分享快速更新资源和排查常见问题的技巧,助你彻底摆脱云端打包的排队依赖,实现高效、可控的应用构建。

weixin_28835551的博客 558

用SimaPro做碳足迹分析:手把手教你完成产品生命周期评估报告

本文详细介绍了如何使用SimaPro进行碳足迹分析,从软件安装到生命周期评估报告的完整流程。通过实战案例演示,帮助制造业企业、咨询机构和科研团队掌握产品生命周期评估(LCA)的核心技术,精准识别环境热点并优化决策,为可持续发展转型提供科学依据。

yhn45678901的博客 715

Java 高频面试:2个线程分别依次输出数字和字母

如题:假设有A、B 2个线程,分别依次输出1a2b3c4d,A线程输出数字,B线程输出字母。 下面有几种方法,感觉方法1是最容易想到的。 方法1:synchronized 和 wait/notify /** * 使用 synchronized 和 wait notify */ private static void func1() { char[] num = new char[]{'1', '2', '3', '4'}; char[] str =

zhujiangtaotaise的专栏 519

200Gb/s以上速率的通道信号完整性设计和优化经验(二)

为满足200Gb/s信号完整性需求,需综合优化PCB、连接器、封装及SERDES架构。关键措施包括:采用低粗糙度铜箔与低损耗材料降低传输线损耗(200G目标0.55–0.6dB/cm);通过背钻工艺控制残桩长度至4±2mil;缩减连接器焊盘残桩至600μm以内以消除谐振;封装层面推进跳层走线、低Dk/Df材料与可控SMT工艺;采用PAM4调制与基于ADC/DSP的混合信号架构实现高效均衡。先进CMOS工艺(如纳米片器件)支撑复杂数字处理,协同设计是突破速率瓶颈的核心。

小孟同学的博客 148

java1a2b3c4d5e6f_【马士兵公开课】面试题。用两个线程,一个输出字母,一个输出数字,交替输出。1A2B3C4D5E6F7G...

package com.zillion.springcloudeurekaserver;import org.junit.Test;import java.io.IOException;import java.io.PipedInputStream;import java.io.PipedOutputStream;import java.util.concurrent.ArrayBlocking...

weixin_39709979的博客 247

数仓建模:维度表合并时,如何处理可能出现的数据冲突?

通过以上方法,可以有效地处理维度表合并时可能出现的数据冲突,确保合并后的数据完整性、一致性和准确性,满足业务需求和数据仓库的性能要求。在合并过程中,需要根据实际情况选择合适的处理方法,并进行充分的测试和验证。(2)实战中总结的SQL技巧,帮助SQLBOY在SQL语言上有质的飞越,无论你应对业务难题及面试都会游刃有余【如果您觉得本文还不错,对你有帮助,那么不妨可以关注一下我的数字化建设实践之路专栏,这里的内容会更精彩。技巧总结,让你认识不一样的数仓。,数据库会抛出异常,可根据异常处理机制解决。

石榴姐yyds 1132

MATLAB基础应用精讲-【强化学习】Actor - Critic 算法(附python代码实现)

这种架构结合了策略梯度方法(Policy - Gradient Methods)和价值函数估计方法(Value Function Estimation Methods)的优点。在强化学习中,智能体(Agent)需要通过与环境(Environment)的交互来学习最优的行为策略,以获得最大的累积奖励(Cumulative Reward)。

qq_36130719的博客 363

线程通信的例子:使用两个线程打印1-100.线程1,2交替打印

线程通信的例子:使用两个线程打印1-100.线程1,2交替打印 package Java; //线程通信的例子:使用两个线程打印1-100.线程1,2交替打印 class Number implements Runnable{ private static int number = 1; @Override public void run() { while (true){ if (number < 100) { System.o

HenryFanQAQ的博客 449

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

面试必问!Java 多线程中两个线程交替执行,一个输出偶数,一个输出奇数

前言 楼主今天在面经上看到这个题,挺有意思,小小的题目对多线程的考量还挺多。大部分同学都会使用 synchronized 来实现。楼主今天带来另外两种优化实现,让你面试的时候,傲视群雄! 第一种 synchronized class ThreadPrintDemo2 { public static void main(String[] args) { final ThreadPrint...

weixin_34137799的博客 413

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

几种交替打印线程的方式

一、利用synchronized,notify,wait public class Main { public static void main(String[] args) { Object o = new Object(); Thread str = new Thread(() -> { try { Thread.sleep(100); } catch (Interrupted

OriSu 334

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

八:深入理解 Condition —— 线程通信(等待/通知)

当一个持有锁的线程调用将当前线程加入到条件等待队列中,状态为【CONDITION】彻底释放锁,并唤醒同步队列中阻塞的一个线程判断自己是否在同步等待队列中,如果不在,将自己阻塞起来如果被signal()方法唤醒了,则去竞争同步锁当一个持有锁的线程调用删除条件等待节点的头节点将头节点添加到同步等待队列的 tail 之后,如果添加成功,则退出循环;否则,如果条件等待队列中还有节点,则后移,循环步骤 1、2修改头结点的状态【CONDITION => 0】

sco5282的博客 1312

Java并发编程:CountDownLatch原理与应用实战

在Java并发编程中,线程同步是确保多线程安全协作的核心机制。CountDownLatch作为JUC包中的重要工具,采用计数器机制实现线程等待/通知模式,其底层基于AQS框架保证线程安全。通过volatile变量维护计数器状态,确保内存可见性,countDown()和await()方法分别实现计数递减和阻塞等待。这种设计特别适合多线程任务协调、服务启动依赖管理等场景,相比CyclicBarrier具有不可重置但更高性能的特点。在分布式计算和微服务架构中,合理使用CountDownLatch能有效解决线程同步

weixin_30619101的博客 427

复习Java,看了还不错的,资料搜集笔记

CountDownLunch(闭锁)、CyclicBarrier(栅栏锁)、Semaphore(信号量)的区别。分区只是一张表中的数据的存储位置发生改变,分表是将一张表分成多张表。分区和分表的目的都是减少数据库的负担,提高表的增删改查效率。当访问量大,且表数据比较大时,两种方式可以互相配合使用。当访问量不大,但表数据比较多时,可以只进行分区。作者不错:云扬四海(腾讯云社区)作者:HongXuan-Yuan。包含Phaser和exchange。todo 不会 字节流字符流。:如何实现按照指定顺序执行线程。

weixin_45438577的博客 1134

线程池拒绝策略详解:原理、应用与实战技巧

线程池作为Java并发编程的核心组件,其拒绝策略是保障系统稳定性的关键机制。从技术原理看,当线程池的工作队列和最大线程数达到上限时,拒绝策略决定了如何处理新提交的任务。常见的四种策略包括直接抛出异常的AbortPolicy、由调用线程执行的CallerRunsPolicy、静默丢弃的DiscardPolicy以及丢弃最老任务的DiscardOldestPolicy。在高并发场景下,合理选择拒绝策略能有效防止OOM、实现快速失败和弹性降级。例如电商大促时,CallerRunsPolicy能通过负反馈机制平滑流

weixin_30719711的博客 404

Rust中高效使用SHA2哈希算法:从基础到性能优化实战

加密哈希函数是计算机安全与数据完整性校验的核心基础技术,它通过单向数学变换将任意长度数据映射为固定长度的摘要值。其原理基于压缩函数迭代,确保数据的微小变动会导致哈希值的巨大差异,从而提供数据防篡改和唯一性验证能力。在工程实践中,哈希算法广泛应用于密码存储、数字签名、区块链和数据去重等场景。Rust语言凭借其内存安全和高性能特性,成为实现密码学组件的理想选择。通过digest trait提供的统一接口,开发者可以灵活选用SHA2等算法家族,并结合hex编码、流式处理等工具链,构建高效可靠的哈希计算模块。本文聚

wentao365的专栏 558

uuid-creator工厂模式源码解读:如何自定义时间函数、节点ID与时钟序列

**uuid-creator** 是一个开源的 Java UUID 生成库,支持从 UUIDv1 到 UUIDv7 的全部标准标识符。它的核心设计是**工厂模式**:每一类 UUID 都由一个专属工厂生成,而时间型 UUID(v1/v2/v6)的工厂又通过三个可插拔函数——时间函数、节点ID函数、时钟序列函数——实现完全自定义。本文带你读懂这套工厂架构,并学会如何替换其中的任意组件。 ## 一、

gitblog_00550的博客 417

Arthas 4.x 与 JProfiler 性能分析对比:5个关键场景下的工具选型指南

本文深入对比了Arthas 4.x与JProfiler在Java应用性能分析中的表现,涵盖CPU使用率飙升、内存泄漏诊断、方法耗时分析等5个关键场景。Arthas以其轻量级和无侵入性优势适合线上即时诊断,而JProfiler则擅长开发阶段的深度性能剖析。文章提供了详细的工具选型指南,帮助开发者根据实际需求选择最合适的性能分析工具。

weixin_34007020的博客 416
上一篇: Java创建线程的几种方式
小菜大白
博客等级 码龄10年 4粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值