??xml version="1.0" encoding="utf-8" standalone="yes"?>
1.E序如果只有后台q程而没有一个前台进E,那么整个javaE序׃l束。用setDaemon(true)可以把线E设为后台线E,普通创建的U程都是前台U程?BR>2.一个线E类l承Threadc,q个子类实现runҎQrunҎ处理的事物的处理。启动线E用startҎ。[threadcLw的runҎ是空的,所以需要子cd实现QstartҎ也是threadc里l承q来的,׃java的多态性,所以startҎ会启动子cȝrunҎ]
3.join()Ҏ可以合ƈU程Q如果不带参数表C永久合qӞ如果带参数表C线E合q多豪U后又分开执行
class ThreadDemo
{
public static void main(String [] args)
{
Thread tt = new TestThread();
//tt.setDaemon(true);把线Ett|ؓ后台U程
tt.start();//q个Ҏ会自动去调用tt的runQ)
int index = 0;
while(true)
{
if(index++ == 100)//执行100ơ后合ƈU程
try{tt.join(10000);//把ttU程合ƈCU程10U?如果q里是没有参敎ͼ那么永q执行runq?nbsp; //个线E,因ؓq个U程是个d@环,下面的语句就执行不到了,哈哈} catch(Exception e){}
System.out.println("main()"+Thread.currentThread().gerName()//得到当前执行U程的名?;
}
}
}
class TestThread extends Thread
{
public void run()
{
while(true)
{
System.out.println("run()"+Thread.currentThread().gerName()//得到当前执行U程的名?;
}
}
}
以上说了如何用承ThreadcL创徏U程Q还有一U方法是cL实现Runnable接口来创建线E?BR>class TestThread extends Thread q个pҎ class TestThread implements Runnable
而main中的Thread tt = new TestThread(); pҎ Thread tt = new Thread(new TestThread());q里接受的类型是Runnable型的
那么出C一个问题,既然两种Ҏ都可以创建线E,那么有什么区别呢Q我们来看一个铁路模拟售系l:
?00张票Q我们启?个线E来卖他们:
class ThreadDemo
{
public static void main(String [] args)
{
/* 如果用这U写法,你会发现实际是启动了4个线E,然后4个线E都有各自的100张票Q各买各的,所以这h错的?BR> new TestThread();
new TestThread();
new TestThread();
new TestThread(); */
/*如果是这U写法,从输出结果中我们发现无论start了多次Q实际还是一个线E,所以这样也是错的?BR> TestThread tt = new TestThread();
tt.start();
tt.start();
tt.start();
tt.start();
*/
}
}
class TestThread extends Thread
{
int tickets = 100;
public void run()
{
while(true)
{
if(tickets>0)
System.out.println(Thread.currentThread().gerName()+"is saling ticket "+tickets--);
}
}
}
q种情况下我们就使用runnable了。请看:
class ThreadDemo
{
public static void main(String [] args)
{
TestThread tt = new TestThread();
new Thread(tt).start();//四个U程调用同一个线E对?BR> new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
}
}
class TestThread implements Runnable
{
int tickets = 100;
public void run()
{
while(true)
{
if(tickets>0)
System.out.println(Thread.currentThread().gerName()+"is saling ticket "+tickets--);
}
}
}
ȝQ用runnable接口创徏多线E比l承thread要灵zR他适合多个相同的程序代码的U程d理同一资源的情c?/P>
多线E的应用Q?BR>1.|络聊天工具开?BR> 一个线E负责发消息Q一个负责收消息。两者互不干扎ͼ如果是单U程Q那么就可能前面在等待,而后面就接收不了消息?BR>2.大量数据库记录的复制?BR> 如果一个复制要?天时_那么当你中途觉得没有必要,要停止的时候,你发C不能让他停下来。而多U程的情况,一?BR> 现成负责拯Q是个无限@?BR> while(bStop)
{get data
copy data}
另一个现成监督是否有键盘按下Q也是把原本ؓtrue的变量bstop|ؓfalse?nbsp; bStop = false;当另一U程监视到变?nbsp; 变化时会停止E序
3.www服务器ؓ每一个来访者创Z个线E?/P>
U程安全问题Q?BR>我们在上面做的铁路模拟兽系l有个问题:U程安全问题Q?BR>假如当tickets==5的时Q系l正好正好要执行tickets--Q而还意执行q个的时候,cpu被切换到另一个线E。那么tickets仍然?Q所以很?q张打C2ơ,另一U情况:当票?的时候系l刚好要打印?Q而这个时候cpu马上切换C其他U程Q它发现还?Q所以通过了判断大?Q所以打印出了票1。而这个时候票--?Qcpu切换C刚才的线E,׃刚才的线E在执行打印Q所以把?l打印出来,q些都造成了线E的安全问题
所以我们要把if语句块作Z个原子,攑ֈsynchronized()里面。synchronized()里面必须有参敎ͼ比如
String str = new String("");
然后把if语句块放到synchronized(str){ if... }里面 q样实C同步Q避免了U程的不安全?BR>另外Q我们如果希望一个方法是U程安全的,那么我们可以直接在方法名前写上synchronized关键字,比如Q?BR>public synchronized void sale(){......} //实际上这U情况下synchronized使用的同步对象是this
注意Qstr的定义必L到runҎ之外Q这个对象应该是全局的,q样才能作ؓ锁旗标!Q系l会自动对这个对象进行标识)
U程执行的内部机Ӟ
new Thread(tt).start();
执行startq没有马上去执行U程的runҎQ而是再向下l执行一会,因ؓcpuq没有这么快切换到U程上,要想让他马上切换Q可以在start后写上:try(Thread.sleep(1);//哪怕是一U,他也会切?catch(Exception e){}
如果把代码块的同步用synchronized(this),那么代码块会和有synchronized的方法同步!
1Q?1 为止 5
cM下面的代码在多线E调用它的时候也要注意线E安全问题:
public void push(char c)
{
data[index] = c;
index++;
}
另外有一场景[U程间通信问题]Q生产者不停地产生一l数据,消费者不停地d数据Q数据都在缓存中Q?BR>class Producer implements Runnable
{
Q q;
public Producer(Q q)
{
this.q = q;
}
public void run()
{
int i = 0;
while(true)
{
if(i==0)
{q.name = "zhangsan";
try{Thread.sleep(1);}catch(Exception e){}//用sleep来模拟cpu切换的现?BR> q.sex = "male";
}
else
{q.name = "lisi";
q.sex = "female";
}
i = (i+1)%2; //使i??之间切换
}
}
}
class Customer implements Runnable
{
Q q;
public Customer(Q q)
{
this.q = q;
}
public void run()
{
while(true)
{
System.out.println(q.name);
System.out.println(":"+q.sex);
}
}
}
class Q
{
String name = "unknow";
String sex = "unknow";
}
//run class
class ThreadCommunation
{
public static void main(String [] args)
{
Q q = new Q();
new Thread(new Prodecer(q)).start();
new Thread(new Customer(q)).start();
}
}
q行后我们会发现名字和性别q没有对应v来,q是因ؓU程没有同步的问题,要解册个问题,只需要在两个cȝwhile?BR>分别加上synchronized(q){}语句块,因ؓ他们都用同一个对象qQ所以用q作ؓ同步监视?BR> 上面的代码还不是很完善,因ؓ有当消费者取得同步监视器却发现缓冲区Ҏ没有数据的情况,那怎么办?或者当生者在
取得同步监视器开始生产数据的时候又取得了同步监视器开始放数据Q这样就会把原先的数据覆盖!我们使用了wait和notify
对程序修改如下:
class Producer implements Runnable
{
Q q;
public Producer(Q q)
{
this.q = q;
}
public void run()
{
int i = 0;
while(true)
{
synchronized(q)
{
if(q.bFull)//如果~冲区是满的 有数据的 那么生者线E应该wait{待消费者来取数?BR> try{q.wait();}catch(Exception e){}
if(i==0)
{q.name = "zhangsan";
try{Thread.sleep(1);}catch(Exception e){}//用sleep来模拟cpu切换的现?BR> q.sex = "male";
}
else
{q.name = "lisi";
q.sex = "female";
}
q.bFull = true;
q.notify();//通知消费者有数据要他来取数据
}
i = (i+1)%2; //使i??之间切换
}
}
}
class Customer implements Runnable
{
Q q;
public Customer(Q q)
{
this.q = q;
}
public void run()
{
while(true)
{
synchronized(q)
{
if(!q.bFull) //~冲ZؓI的时候交出同步监视器开始等?BR> try{q.wait();}catch(Exception e){}
System.out.println(q.name);
System.out.println(":"+q.sex);
q.bFull = false; //取走数据后缓冲区为空
q.notify(); //通知生者线E开始执行,q个notify与Producer中的wait对应
}
}
}
}
class Q
{
String name = "unknow";
String sex = "unknow";
boolean bFull = false;
}
//run class
class ThreadCommunation
{
public static void main(String [] args)
{
Q q = new Q();
new Thread(new Prodecer(q)).start();
new Thread(new Customer(q)).start();
}
}
注意Qwait和notifyҎ必须是synchronized的监视器对象的方法,既如果有
synchronized(q),那么应该q.wait();q.notify(); 如果不写对象Q他会默认是this对象
而有可能Dq行旉误[~译没有错误]
M对象都有wait,notify,notifyAllҎQ?BR>waitQ告诉当前线E放弃监视器q进入睡眠状态直到其他线E进入同一监视器ƈ调用notify为止Q?BR>notifyQ唤醒同一对象监视器中调用wait的第一个线E?BR> 用于cM饭馆有一个空位后通知所有等候就的֮中的W一位可以入座的情况?BR>notifyAllQ唤醒同一对象监视器中调用wait的所有线E。具有最高优先的线E首先被唤醒q执行?BR> 用于cM某个不定期的培训班终于招生满额后Q通知所有的学员都来上课的情c?/P>
实际上上面的代码有些乱,q是因ؓE序的结构设计不够合理,应该把数据的攑֒取放到qcMQ然后在
q两个方法名前加上关键字synchronizedQ类?BR>public synchronized void put(String name,String sex)
{
if(bFull)
try{wait();}catch(Exception e){}
this.name = name;
try{Thread.sleep(1);}catch(Exception e){}
this.sex = sex;
bFull = true;
notify();
}
我们l别人提供的cLU程安全的,cM上面的代码。别人在使用q个cȝ时候就不需要考虑U程安全问题Q反之,需要在
外面处理U程安全问题
控制U程的生命周期:
class ThreadLife
{
public static void main(String [] args)
{
ThreadTest tt = new ThreadTest();
new Thread(tt).start();
for(int i=0;i<100;i++)
{
if(i==50)
tt.stopMe();
System.out.println("main() is runing");
}
}
}
class ThreadTest implements Runnable
{
private boolean bStop = false;
public void stopMe()
{
bStop = true;
}
public void run()
{
while(!bStop)
{
System.out.println(Thread.currentThread().getName()+"is running");
}
}
}
byte b = 3;
b = b - 1;
以上写法错误 因ؓ如果表达式中有int型数字,那么所有的byte QshotQchar的值都被提升到intQ同PlongQfloat, double也是如此
System.out.println('a'+1); l果?8
System.out.println(""+'a'+1); l果是a1
static void drawTech(int x,int y)
{.........}
q个Ҏ可以直接使用而不需要newQ比如在mainҎ中写drawTech(3Q?Q;
System.out.println("2+5="+getAres(2,5));而不?BR>System.out.println("2+5="QgetAres(2,5));
非法参数的检查用return;直接q回
函数的重载就是在一个类中允许同时存在一个以上的同名函数Q只要它们的参数个数或者类型不同即?/P>
数之间的除 l果会保留小数部?BR>整数之间的除 l果抛弃数部分
-------------------------
int x=5,y;
int y=x/2;//l果?
--------------------------
int x=5,y;
float f=x/2;//l果?.0
----------------------------
int x=5,y;
float f=QfloatQx/2;//l果?.5 q里发生了表辑ּ数据cd提升
------------------------------------------------------------
int x=3510;x=x*1000/1000; l果?000
----------------------------------------
int x=5,y;
y = x%2;//l果?1
--------------------------------
int x=5,y;
y = -x%2;//l果?-1
-------------------------------
int x=5,y;
y = x%-2;//l果?1 表示取摸?摸数如果是负?那么负号忽不计算
--------------------------------------
安排戉K题目Q共有x个学生,每个戉K?人,用一个公式计他们要住的戉K敎ͼ
解答Q有些h是x/6+1Q?昄在x?0的时候就不对了,正解是:Qx+5Q?6Q?BR>q种法q可以用在查看留a版的分页昄上,x是ȝa敎ͼ6是每|C数Q结果就是d多少面
-----------------------------------------------------------------------------------
假设要让x的值在0?之间循环变化Q写Z码:
int x=0;
while(true)
{
x=(x+1)%10;
}
q个可以用在循环10副图的显CZ
-------------------------------------
x = 0x80000000;
y = x>>1;//有符L位最高位补的是原来的最高位Q原来是1p1Q是0?
System.out.println(Integer.toHexString(y));//int的y转化?6q制
y = x>>>1;//无符L无论原来?q是0都补0
System.out.println(Integer.toHexString(y));//int的y转化?6q制
-----------------------------------------------------------------------
byteQshort,char,int,long都可以移位运?BR>低于int的操作数先自动{int再移
int型移 最多移31位,因ؓint最大是32位的 pȝ操作数?2取模Q得到的l果才是真正的依的位敎ͼa>>33 和a>>1l果是一L
long型是?4取模
x>>1和x/2l果一?nbsp; x<<2和x*4l果一?BR>-----------------------------------------------------
从键盘读取输入字W的整数值System.in.read();
以下代码Z断读入键盘|如果是qQ那么退出,如果不是qQ打印字W?BR>try
{
x=System.in.read();
}
catch(Exception e){}
while(x!='q')
{
System.out.println((char)x);
try{
x=System.in.read();
}
catch(Exceotion e){}
}
---------------------------------
声明数组可以Q一开始就Ҏl赋值的叫静态数l?BR>int a[]={1,2,3};
也可?BR>int []a=new int[]{1,2,3}
如果没有赋|比如
int []a=new int[]Q?BR>打印出来默认的全?
如果q么定义一个数lint [] y;然后拿来用那么是~译通不q的Q因为没有初始化Q一个数l没有初始化Q也没有指向堆中的Q何地方,所以也没有默认?BR>------------------------
int a[4];//声明数组?不能指定长度Q编译将出错。和c不一?BR>---------------------------------------------------------
int[] x=new int[100];
x= null;
x[1]=3;
q样的代码编译通过Q运行出错:I指针错误?因ؓx数组指向的是I,所以就没有所谓的W一个元素第二个元素 q点需要注?BR>同理Q当我们调用一个返回的对象的功能时Q如果不对这个对象进行检查,而这个对象是I,那么可能是q种I指针异?BR>-----------------------------------------------------------------------------------------------------
遍历二维数组
int [][] xx = new int[2][3];
for(int i=0;i<xx.length;i++)
{
for(int j=0;j<xx[i].length;j++)
{
System.out.println(xx[i][j]);
}
}
-----------------------------------------
int []a=new int[]{9,4,3,8};
Arrays.sort(a);//从小到大排序
2下结?/P>