public class JoinThread extends Thread
{
static int i = 0;

public JoinThread(String name)
{
super(name);
}
public void run()
{
while(i < 100)
{
i++;
System.out.println(getName() + " " + i);

}
}

public static void main(String[] args)throws Exception
{
JoinThread t = new JoinThread("后台");
t.start();
while(i<100)
{
System.out.println(Thread.currentThread().getName() + " " + i);
}
System.out.println("停");
}
}
====================================================================================
运行结果是这样的 
后台 1
后台 2
main 1
main 3
后台 3
main 3
后台 4
 .........
main 97
后台 98
main 98
后台 99
main 99
后台 100
停================================================================================   问题一:为什么运行结果不是这样
后台 1
后台 2
main 3
main 4
后台 5
main 6
后台 7
 .........
main 95
后台 96
main 97
后台 98
main 99
后台 100
停================================================================== 问题一:  怎么只有 一个i 会在不同的线程里面出现不同的值呢? 问题二:  i的内存内部是怎么实现的?想不通怎么一个变量会在不同线程中展示出两个不同的值。

解决方案 »

  1.   

    package me.luger.base;import java.util.Scanner;//www.luger.me
    public class Test extends Thread {
    static int i = 0;
    static Object o = new Object(); public Test(String name) {
    super(name);
    } public void run() {
    while (i < 1000) {
    System.out.println(getName() + " " + i);
    i++;
    Thread.yield(); }
    } public static void main(String[] args) throws Exception { Test t = new Test("后台");
    t.start();
    while (i < 1000) {
    System.out.println(Thread.currentThread().getName() + " " + i);
    i++;
    Thread.yield();
    }
    System.out.println("停");
    }
    }
    试试这个
      

  2.   

    package me.luger.base;import java.util.Scanner;//www.luger.me
    public class Test extends Thread {
    static int i = 0;
    static Object o = new Object(); public Test(String name) {
    super(name);
    } public void run() {
    while (i < 1000) {
    synchronized (o) {
    System.out.println(getName() + " " + i);
    i++;
    Thread.yield();
    } }
    } public static void main(String[] args) throws Exception { Test t = new Test("后台");
    t.start();
    while (i < 1000) {
    synchronized (o) {
    System.out.println(Thread.currentThread().getName() + " " + i);
    i++;
    Thread.yield();
    }
    }
    System.out.println("停");
    }
    }
    还有这个 ,对线程我也有点乱 坐等高手解决一下
      

  3.   


    我是这么理解的,不知道有没有问题你这两个线程主要运行的:
    A:
    while(i < 100)
     {
     i++;
     System.out.println(getName() + " " + i); }B:
    while(i<100)
     {
     System.out.println(Thread.currentThread().getName() + " " + i);
     }cpu的时间片切换本来就不是一定执行一次A->B->A->B这样的顺序
    很可能是A->A->B->ASystem.out.println(Thread.currentThread().getName() + " " + i);
    这个操作是两步,你可以理解成
    String str = Thread.currentThread().getName() + " " + i;
    System.out.println(str);
    那如果在这两步中间出现了时间片的切换,就会产生你现在的现象
      

  4.   

    2楼的代码好强悍,不过楼主没要求 后台 和 main 的打印信息交替出现,
    所以 Thread.yield()应该是不用的,只要有那个同步块(synchronized (o) { ......})就行了
      

  5.   

    问题一:    你的程序中你虽然自己定义了一个线程JoinThread t = new JoinThread("后台");可是main()方法本身就是一个线程,指向程序的过程中,你定义的线程你控制启动,可是启动后线程就不受你的控制,而系统会给我们产生一个主线程,main 方法就在主线程上运行,而这两个线程执行都是随机的,所以你每执行一次,产生的结果都不不同。除非你给一个对象加上一个锁,Java中的每个对象都有一个锁(lock)或者叫做监视器(monitor),当访问某个对象的synchronized方法时,表示将该对象上锁,此时其他任何线程都无法再去访问该synchronized方法了,直到之前的那个线程执行方法完毕后(或者是抛出了异常),那么将该对象的锁释放掉,其他线程才有可能再去访问该synchronized方法。这样就能按一定的顺序输出。
     问题二:在执行线程的过程中,那个线程抢上这个变量,就执行那个线程。一个线程执行时,另一个线程就等待,除非它获得变量在执行。
      

  6.   

    你的代码输出有顺序主要在于关键字synchronized:
    synchronized关键字:当synchronized关键字修饰一个方法的时候,该方法叫做同步方法。
       Java中的每个对象都有一个锁(lock)或者叫做监视器(monitor),当访问某个对象的synchronized方法时,表示将该对象上锁,此时其他任何线程都无法再去访问该synchronized方法了,直到之前的那个线程执行方法完毕后(或者是抛出了异常),那么将该对象的锁释放掉,其他线程才有可能再去访问该synchronized方法。
       如果一个对象有多个synchronized方法,某一时刻某个线程已经进入到了某个synchronized方法,那么在该方法没有执行完毕前,其他线程是无法访问该对象的任何synchronized方法的。   synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法,有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,直接运行。它包括两种用法:synchronized 方法和 synchronized 块。
    1. synchronized 方法:
      声明是为了定义变量的作用范围和作用域
      通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如:
      public synchronized void accessVal(int newVal);
      synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。
      在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问。
      synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块。