进程:是正在运行的程序
线程:是进程中的单个控制流,是一条执行路径
代码示例
MyThreadDemo.java
package THREAD;
public class MyThreadDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread th1=new MyThread();
MyThread th2=new MyThread();
th1.start();
th2.start();
}
}
MyThread
package THREAD;
public class MyThread extends Thread {
public void run() {
for(int i=0;i<100;i++) {
System.out.println(i);
}
}
}
long getId()
返回此线程的标识符。
String getName()
返回此线程的名称。
int getPriority()
返回此线程的优先级。
void setName(String name)
改变该线程的名称等于参数 name。
void setPriority(int newPriority)
更改此线程的优先级。
static void sleep(long millis)
当前正在执行的线程休眠(暂停执行)为指定的毫秒数,根据精度和系统定时器和调度的准确性。
static void sleep(long millis, int nanos)
当前正在执行的线程休眠(暂停执行)为指定的毫秒数加指定数纳秒,受制于系统的高精度定时器和调度的准确性。
void start()
导致该线程开始执行;java虚拟机调用这个线程的 run方法。
static void yield()
给调度程序的一个提示,当前线程愿意得到它当前的处理器的使用
void join(long millis, int nanos)
等待最多 millis毫秒加上 nanos纳秒这个线程死亡
boolean isDaemon()
测试这个线程是否是守护线程
void interrupt()
中断这个线程
void setDaemon(boolean on)
将此线程标记为 daemon线程或用户线程
static Thread currentThread()
返回对当前正在执行的线程对象的引用
ThreadSleep
package THREAD;
public class ThreadSleep extends Thread{
public void run()
{
for(int i=0;i<5;i++) {
System.out.println(getName()+","+i);
}
}
}
ThreadSleepDemo
package THREAD;
public class ThreadSleepDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
ThreadSleep t1=new ThreadSleep();
ThreadSleep t2=new ThreadSleep();
ThreadSleep t3=new ThreadSleep();
t1.setName("java");
t2.setName("Python");
t3.setName("C++");
t1.start();
t2.start();
t3.start();
}
}
结果
我们发现很乱,如果想要每个线程都交替执行,就可以用sleep来控制,修改ThreadSleep即可
package THREAD;
public class ThreadSleep extends Thread{
public void run()
{
for(int i=0;i<5;i++) {
System.out.println(getName()+","+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
结果
如果想要让java线程运行结束,其他两个线程再运行可以用join()实现
ThreadJoin
package THREAD;
public class ThreadJoin extends Thread{
public void run()
{
for(int i=0;i<5;i++) {
System.out.println(getName()+","+i);
}
}
}
ThreadJoinDemo
package THREAD;
public class ThreadJoinDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
ThreadJoin t1=new ThreadJoin();
ThreadJoin t2=new ThreadJoin();
ThreadJoin t3=new ThreadJoin();
t1.setName("Java");
t2.setName("Python");
t3.setName("C++");
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t2.start();
t3.start();
}
}
结果:
补充: java里有两类线程:用户线程和守护线程,所有守护线程都是为用户线程工作的,只要还有一个用户线程在运行,守护线程就必须运行,当运行的进程都是守护进程时,java虚拟机将退出。
如果我们希望java进程执行结束之后,Python进程和C++进程不再执行了,那就可以将Python进程和C++进程设置为守护线程
ThreadDaemon
package THREAD;
public class ThreadDaemon extends Thread{
public void run() {
for(int i=0;i<5;i++) {
System.out.println(getName()+","+i);
}
}
}
ThreadDaemonDemo
package THREAD;
public class ThreadDaemonDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
ThreadDaemon t1=new ThreadDaemon();
ThreadDaemon t2=new ThreadDaemon();
t1.setName("Python");
t2.setName("C++");
//设置主线程
Thread.currentThread().setName("java");
//设置守护线程
t1.setDaemon(true);
t2.setDaemon(true);
t1.start();
t2.start();
for(int i=0;i<2;i++) {
System.out.println(Thread.currentThread().getName()+","+i);
}
}
}
代码示例:
package THREAD;
public class MyRunnableDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyRunnable mb=new MyRunnable();
//Thread(Runnable target, String name) 分配一个新的 Thread对象。
Thread th=new Thread(mb,"java");
th.start();
}
}
举个栗子 :
假设A和B家里有一个密码箱,里面放了五万现金,他们都有一把开这个箱子的锁,有一天A想要那这五万里的三万去买股票,但怕B知道,他就偷偷去了,所以箱子里还有两万,但B以为里面还是五万,他刚好想拿这五万去装修小屋,便去保险箱去五万,我们当然知道不可能去五万了,但是B不知道,所以这会造成B拿走前之后,保险箱里是负三万,这显然是不合法的!!
在多线程里也是一样,当几个线程共享一个资源的时候,他们会竞争该资源,但彼此永远不知道在自己访问之前,资源还有多少个,每一个线程都可以看成一把锁,他们只知道自己上一次开锁资源的剩余量,并不知道在之后有没有线程使用资源,因为别的线程也有锁,可以打开资源
如何解决该问题?那就是让资源每次只有一个线程访问呗,也就是只有一钥匙,当一个线程拿到钥匙之后,其他线程只能等到该线程是使用完才可以使用,也就是将使用资源那部分代码锁起来,并给所有线程只配备一把锁
将同步代码块锁起来就要synchronized关键字
private Object obj=new Object();
synchronized(obj){
...//同步代码块
}
代码示例:
以买票为例,假设有20张票(资源),有三个销售员(三个线程)一起卖这二十张票
SellTicket
package THREAD;
public class SellTicket implements Runnable{
private int tickets=20;
private Object obj=new Object();//一把锁
@Override
public void run() {
// TODO Auto-generated method stub
while(true) {
synchronized(obj) {
if(tickets>0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
tickets--;
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");
}
}
}
}
}
SellTicketDemo
package THREAD;
public class SellTicketsDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
SellTicket st=new SellTicket();
Thread th1=new Thread(st,"1");
Thread th2=new Thread(st,"2");
Thread th3=new Thread(st,"3");
th1.start();
th2.start();
th3.start();
}
}
如果不加同步代码块的锁,我们看看执行情况:
可以发现,多个销售员在出售同一张票,这显然不合理,而且居然有负数个票
加锁之后