java线程for循环没有循环完成就停止了,这是为什么?

public static void main(String[] args) throws InterruptedException {
final List<Integer> list = new ArrayList<Integer>();
// final Vector<Integer> list = new Vector<Integer> ();
// final List<Integer> list = Collections.synchronizedList(list1);
// 线程A将0-1000添加到list
new Thread(new Runnable() {
public void run() {
synchronized (list){
for (int i = 0; i < 1000 ; i++) {
list.add(i);

try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();

// 线程B将1000-2000添加到列表
new Thread(new Runnable() {
public void run() {
synchronized (list) {
for (int i = 1000; i < 2000; i++) {
list.add(i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

}
}).start();

Thread.sleep(1000);

// 打印所有结果
for (int i = 0; i < list.size(); i++) {
System.out.println("第" + (i + 1) + "个元素为:" + list.get(i));
}
}

多线程需要基础学好点。在来开发,否则总有莫名其妙的事情冒出来。而自己无法解释。
你这个问题很简单。
你要main主线程1秒后输出list集合数据。在你代码中这写法本身是错误的,因为你有2个子线程,有锁,安全地往list中加2千个数据,却每次要等待1毫秒,估算2千数据你程序的加完需要2秒多时间,在1秒后,子线程还没有结束,大概1千个数据还没加完呢,你主线程就输出了当前数据。肯定结果不对。哪来的2千个数据呢。你说循环没完成就停止了,说法完全错误。。。
你要main主线程输出list集合数据。正确操作应该是:
Thread t1 = ...;
t1.start();
t2也是如此。
最后main线程下面,输出list数据前加2行代码
t1.join();
t2.join();
然后在打印list。
join方法意思很简单。就是等待线程结束后,我再继续。main线程等待了2个子线程都结束后,即保证数据全部进list后,打印结果。追问

List list = new ArrayList();改成Vector list = new Vector就会全部打印出来,你知道是为什么?

追答

多线程之间 共享变量操作 需要加锁,就是并发编程,你自己2子线程加list锁也是一样的道理啊,

你用了vector。那是线程安全的,早起的java版本简陋,粗暴,性能低。你看为了线程安全,简单的在方法上加一个synchnized就搞定了。那很明显,主线程输出时同样使用了 本身对象作为锁。跟你2个子线程是同一把锁。肯定能输出全,为什么,因为主线程你get一次要抢一次锁,这样主线程要抢多次锁,而2子线程都只要抢一次锁。如果2子线程 改为 private static final Object LOCK = new Object()。使用LOCK锁,则你使用vector都打印不全。你自己分析就知道了。自己分析。多线程,和锁。看源码就知道了。

追问

我还是不太懂,我也不知道为什么使用了LOCK就锁不住了,我就知道vector是线程安全的,才能锁住,哈哈,你能给我解释解释为什么lock就锁不住了,你说主线程get一次要抢一次锁,而2子线程都只要抢一次锁,这句话我听不明白,我想知道他们三个是如何抢list锁的

追答

你 根据 多线程 和 锁 的 执行 过程 分析 代码。理论要先学好。

1、多线程

各线程自己同时运行(cpu太快,你可以理解为同时),各不相干。但遇到多线程同时修改同一变量,会发生并发问题。为什么,深层是计算机内存原理,JMM原理。为了解决这问题,所以用锁。

2、锁

单线程是安全的。代码加锁了以后,线程想要执行代码,就要获取锁,代码执行完,锁释放。

锁分很多种。可以根据用途特性分为几个类型。

乐观锁 和 悲观锁。

共享锁 和 排他锁。(读写锁:读锁,设计为共享锁,同时读,效率高,线程不等待。写锁,只能一个线程操作,代码变为单线程顺序执行。保证变量安全。所以一般都是排他锁。)

公平锁 和 非公平锁。公平:多个线程之间顺序轮流拿锁,每人排队拿锁。每人执行同样的次数,每个线程都能执行,公平,不公平锁:每次有锁释放时,CPU随机分配一个线程拿锁。很简单,那样有可能一个线程等半天拿不到锁情况。这就是跟那个故事一样的道理,就是一个

猴子坐在电脑前,不停的敲键盘,只要时间够长,他可以敲出一部莎士比亚小说集。

可重入锁 和 不可重入锁。大部分都是可重入锁。



sychronized 是 排他锁,悲观锁,不公平锁,可重入锁。

你的2个问题。

1、使用Vector,你2子线程都用list锁,主线程读list,就是三个线程都用的list这个对象的对象锁,就是同一个锁。

子线程代码你自己看,循环是在同步锁里面的,抢到锁以后,循环时不需要抢锁,因为是可重入锁,执行完,线程就结束了,线程结束了,锁也释放了,只要抢1次锁就结束了。

main主线程,每次循环调用size()方法抢锁,执行完,释放锁,然后get(i)又抢锁,然后又释放锁,循环1次抢2次锁。所以抢N次锁。

2、为什么2子线程用LOCK锁了,主线程Vector list也打印不全。这很简单啊。此时主线程用list锁,和子线程的大锁LOCK不是同一个锁,但是和子线程里的add是同一把锁,都是对象锁list。

这样子,2子线程和main主线程要抢锁。但是代码你看。这时候子线程要等1毫秒的。主线程1秒后启动,此时大概有900个数据进list了。主线程也要开始抢锁了,但是2个子线程都在睡眠中。(为啥都在睡眠中,请仔细思考这里),

主线程每次循环抢2次锁,没人和它抢了,他就把900个数据打印完了,主线程结束了。后面子线程继续往list中加完数据才结束。(自己思考)。2张图看你自己的代码。另外,一口吃不成胖子。搞编程的需要时间,因为大部分人没有那么高的智商。

追问

听你的我把线程1和线程2的关闭了,然后主线程就都打印完了。我刚才试验了一下别的,用synchronize锁的我把主线程的Thread.sleep(1000);去掉以后使用Vector也不管用了,直接主线程就不打印了,用lock锁的去掉Thread.sleep(1000)以后,一开始和线程一二抢锁打印,但是主线程没有打印完,别的线程最后了打印完了就结束了,这是为什么呢?

追答

没看明白你说什么代码,你自己分析代码执行就好了,执行结果肯定是对的,分析不出,按照结果倒着推也是一样的,没有打印很简单,list是空的。你把主线程等待去掉了,不就立马执行了读list吗,数据没写进去就是空的。

温馨提示:内容为网友见解,仅供参考
第1个回答  2020-05-13
可能是线程问题,只有一个线程时,按顺序进行;多个线程时,执行顺序就不好说了

java线程for循环没有循环完成就停止了,这是为什么?
在你代码中这写法本身是错误的,因为你有2个子线程,有锁,安全地往list中加2千个数据,却每次要等待1毫秒,估算2千数据你程序的加完需要2秒多时间,在1秒后,子线程还没有结束,大概1千个数据还没加完呢,你主线程就输出了当前数据。肯定结果不对。哪来的2千个数据呢。你说循环没完成就停止了...

请教java线程池没有运行完就自动退出了,我也没有去关闭。。
线程的调度和使用方式没有任何问题,Thread.sleep(2*1000);也没有任何必要,因为这样写阻塞的只是主线程。问题应该是处在AxsInfoThread类中,是不是这个类的run方法中的任务已经执行完了,或者其内部又开启了新线程。

java重启时没有结束的线程会自动终止吗?
未执行完的线程:如果Java应用在关闭或重启时还有未执行完的线程,Java虚拟机会尝试停止它们。这意味着这些线程将被中止,并且不会完成它们的任务。这可能会导致未完成的数据处理、数据库事务或其他业务逻辑被丢失。因此,重要的是要确保你的应用可以安全地处理这些线程的停止。在一些情况下,你可能需要使用...

JVM关闭时死循环线程会退出吗?
也就是说,如果你这个线程是 non-daemon thread,那么 JVM 不会退出,一直等待你这个线程运行结束,也就是 run() 方法返回,否则 JVM 直接就退出了,你这个线程也就没了,连捕捉 InterruptedException 的机会都没有。默认情况下,一个线程被创建出来是 non-daemon 线程,你可以调用 Thread 类的 setDaem...

java for循环调用同一个线程,可以同时执行吗,不是一个线程全部执行完了...
for循环中只是创建线程对象,线程进入就绪阶段,什么时候执行不一定,而且执行过程中有可能for循环的线程又获取cpu开始循环了。

java 为什么通过标识符控制线程停止无效
cpu在同一时间只能处理一个地方,循环较慢时,主线程得到执行的可能性就较大,就可以设置flag为false,然后再执行子线程时就会停止了。而循环很快时,循环一下子就结束了,也就是说当主线程尝试设置flag为false时,子线程已经运行结束了

关于java多线程的疑问,为何单步没问题的程序去除断点后运行就会有问题...
用测试类跑的吧?测试类的主线程结束之后,容器就直接关掉了,你开的那些线程已经没有运行环境了,所以你让主线程等下在结束,容器保持开启状态,其他线程才能执行完;这个问题在程序正常启动的时候是不存在的。

如何跳出for循环的Java?
这个可以用一个标记吧,在for循环里面对于每一次循环都检查这个标记,如果标记说跳出就break;否则就继续跑; 而你另外一个线程在要求stop时就是给这个标记赋值,告诉它要跳出。用这种共享一个锁的办法,将就玩吧

java 一个线程执行完了,对象还在吗
线程一启用成功,就会自动关闭线程句柄. 但是,如果线程中有死循环.线程是不会运行完就结束的. 因为未跳出子程序.所以结束不了线程.反之,跳出子程序了就说明自动结束了线程. 死循环子程序的解决方法.可以用强制结束线程 ()或用变量来结束线程.

java中,多线程中,有没有可能当一个线程执行一半时候,另一个线程又开始...
在旧的单处理器系统中,各个线程只是占用处理器的一段时间片,因此不会出现一个线程运行到一半的时候,另一个线程又开始。但是,现在的机器一般都是多处理器系统,实现了真正的并行运行,因此这种情况肯定是会发生的。

相似回答