黑马程序员技术交流社区
标题: 关于卖票(谢谢,已解决) [打印本页]
作者: 戎石锁 时间: 2012-8-17 22:54
标题: 关于卖票(谢谢,已解决)
本帖最后由 戎石锁 于 2012-8-20 21:36 编辑
tick不用static修饰时,四个线程输出的数字出现重复,会出现四个线程均售出同一张票的后果。但在tick前加上static定义之后,四个线程输出的数据不重复,是因为static修饰后tick是全局变量的原因么,能不能再帮我深入解释下,有点不太理解。
class Ticket extends Thread
{ private static int tick=100;
public void run()
{
while(tick>0)
System.out.println(currentThread().getName()+"...."+tick--);
}
}
class TicketDemo
{
public static void main(String[] args)
{
Ticket t1=new Ticket();
Ticket t2=new Ticket();
Ticket t3=new Ticket();
Ticket t4=new Ticket();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
作者: 官文昌 时间: 2012-8-17 23:47
本帖最后由 官文昌 于 2012-8-17 23:48 编辑
class Ticket extends Thread
{
private static int tick=100;//首先纠正楼主的一个错误观点,一个变量不是加上static就是全局变量。全局变量也称为外部变量,它是在函数外部定义的变量。 它不属于哪
// 一个函数,它属于一个源程序文件。其作用域是整个源程序。全局变量和局部变量只是作用范围不同。这里加上了static,那这个变量就变成了静态变量,静态变量的一个
//特点就是所用的对象都共享这个变量,当其中一个对象改变了这个变量值,那这个变量的值也就改变了。(我们可以用代码来验证)
public void run()
{
while(tick>0)
System.out.println(currentThread().getName()+"...."+tick--);
}
}
class TicketDemo
{
public static void main(String[] args)
{
Ticket t1=new Ticket();
Ticket t2=new Ticket();
Ticket t3=new Ticket();
Ticket t4=new Ticket();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
验证代码:
public class TestDemo
{
public static void main(String[] args)
{
Test t1=new Test();
t1.run();
Test t2=new Test();
t2.run();
}
}
class Test
{
int i=10;
//static int i=10;
public void run()
{
i++;
System.out.println(i);
}
}
当我们没有加static时,打印结果是:11
11
当我们加了static时,打印结果就变成了:11
12
总结:
静态变量
我们在编写一个类时,本质上是在描述其对象的属性和行为。而没有产生实质上的对象时,程序是不会分配内存空间的。只有通过NEW关键字才会产生出对象,这时,系统才会分配内存空间,方法也可以供给外部调用。
有时候,希望无论是否产生对象或无论产生多少个对象的情况下。某些特定的数据在内存中只有一份。比如:王雷是个对象,有一个属性,年纪,一个方法,写字方法,满洁是另一个对象,有一个属性,年纪,一个方法,讲话方法,但是,无论是王雷还是满洁,都有一个共同的属性,即国别是中国人。那么,此二人共享国别这一属性。不必分别给此二人都单独分配一个国别属性的内存空间了。我们称这种共享变量为静态成员变量。在变量类型前面加上static 关键字即可。
静态变量在内存空间中只有一份,所有对象都共享这一份变量。
可以直接使用类名来访问静态变量,还可以在类的非静态方法中像访问其它非静态变量一样去访问静态变量,甚至不需要产生类的实例对象,只需要类名就可以引用了。
希望对你有帮助~~~~
作者: 胡刚涛 时间: 2012-8-17 23:54
Static修饰的特点是:
1,随着类的加载而加载;2,被所有的对象所共享;3,优先于对象存在;4,可以直接被类名所调用。
因为tick被static修饰后四个线程输出的数据就会不重复,因为tick被所有的对象共享
一般情况不会采取这种方法来解决tick重复的问题 因为被static修饰的还有一个特点就是生命周期太长,随着类的加载而加载,类消失才会消失。
一般是让类实现Runnable接口,具体代码时:
class Ticket implements Runnable
{
Object obj=new Object();
private static int tick=100;
public void run()
{
synchronized (obj) {
while(tick>0)
try {
Thread.sleep(10);
} catch (Exception e) {
// TODO: handle exception
}
System.out.println(Thread.currentThread().getName()+"...."+tick--);
}
}
}
class TicketDemo
{
public static void main(String[] args)
{
Ticket t=new Ticket();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
Thread t3=new Thread(t);
Thread t4=new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
作者: 李知伦 时间: 2012-8-18 00:01
如果一个成员被声明为static,它就能够在它的类的任何对象创建之前被访问,而不必引用任何对象。所以每条线程都会先访问同一个成员变量,也就形成了不重复的结果
如果没有声明为静态,则每个线程,都会开辟一个新的局部变量ticket,是互相独立的。
你可以将方法和变量都声明为static
static 成员的最常见的例子是main( ) 。因为在程序开始执行时必须调用main() ,所以它被声明为static。声明为static的变量实质上就是全局变量
当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例变量共同拥有一个static变量
作者: 张忠豹 时间: 2012-8-18 00:05
class Ticket extends Thread {
private int tick = 100;//关于静态变量的问题,楼上的回答的相当不错。我来回答一下非static修饰的情况
public void run() {
while (tick > 0)
System.out.println(currentThread().getName() + "...." + tick--);
}
}
class TicketDemo {
public static void main(String[] args) {
//在没有static修饰成员变量的时候,每次创建一个Ticket对象,就给该对象分配一个内存空间,这个对象就拥有
//独特的属性tick。所以以下Ticket创建四个对象,四个Ticket对象都拥有不同的tick属性。在打印输出的相互之间不会影响
//也就导致了你所看见的重复值出现
Ticket t1 = new Ticket();
Ticket t2 = new Ticket();
Ticket t3 = new Ticket();
Ticket t4 = new Ticket();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |