一.创建线程的两种方式
1.继承Thread
class MyThread extends Thread{
private static int ticket = 10;
private String name;
public MyThread(String name){
this.name =name;
}
public void run(){
while(this.ticket>0){
System.out.println(this.name+"卖票---->"+(this.ticket--));
}
}
}
2.实现Runnable接口
class MyThread implements Runnable{
private int ticket =10;
private String name;
public void run(){
while(this.ticket>0){
System.out.println(this.name+"卖票---->"+(this.ticket--));
}
}
}
二.线程的5种状态
1.新生状态(创建状态)。在生成线程对象,但是没有调用对象的start()方法时,该线程处于创建状态
2.就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,此时线程具有CPU的执行资格,但是没有CPU的执行权。
3.运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,开始运行run函数当中的代码,此时线程就进入运行状态,处于运行状态的线程既有CPU的执行资格,又有CPU的执行权。
4.阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。此时线程既没有CPU的执行资格,也没有CPU的执行权。
5.死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪转态。
- sleep()与wait()的区别?
如果当前线程进入了同步锁,调用sleep()方法并不会释放锁,其他被同步锁挡住了的线程也无法得到执行,在sleep()指定的时间过后,线程会自动回到就绪状态等待CPU的执行;而wait()方法会释放同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只用其他线程调用了notify()或notifyAll()方法,线程才会回到就绪状态。但是notify()方法并不释放同步锁,只是告诉调用过wait()方法的线程去参与同步锁的竞争,但不是马上得到锁,因为锁在别人手里,别人还没释放。
三.线程的同步
同步与异步有何不同,在什么情况下使用它们?
如果数据在多个线程之间共享并且操作共享数据的代码不止一条时,就需要对共享数据进行同步处理,即某一个线程在操作共享数据时,其他线程无法操作,只到该线程释放共享数据。当应用程序调用一个需要花费很长时间来执行的方法,并且不需要等待返回结果时,就采取异步操作,例如:下载资源。同步的好处和弊端?
好处:解决了线程的安全性问题
弊端:降低了效率,因为同步外的线程都要判断同步锁
1.同步代码块
思路:将操作共享数据的多条代码封装起来
package com.ghs.sort;
public class Demo{
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();
}
}
class Ticket implements Runnable{
int num=100; //所有的线程共用一个num对象
Object obj = new Object();
public void run(){
while(true){
synchronized(obj){
if(num>0){
System.out.println(Thread.currentThread().getName()+"......sale......"+num--);
}
}
}
}
}
同步锁就相当于一个标志位,初始值为1,有线程进去了,值就变为0,只有当同步锁为1的时候,其他线程才能进去。
2.同步函数
public class Demo {
public static void main(String[] args) {
BankRun br = new BankRun();
Thread t1 = new Thread(br);
Thread t2 = new Thread(br);
t1.start();
t2.start();
}
}
class BankRun implements Runnable {
Bank b = new Bank();
public void run() {
b.add(100);
}
}
class Bank {
private int sum;
//模拟存钱的过程
public synchronized void add(int num) { //此处存在安全问题,采用同步函数来解决
sum = sum + num;
System.out.println(Thread.currentThread() + "......Total=" + sum);
}
}
注意:
1. 同步函数的锁是this
2. 静态同步函数的锁是Class对象而不是this,因为静态函数没有所属的对象
当一个线程进入一个对象的synchronized方法后,其他线程是否可以进入此对象的其他方法?
1. 其他方法前如果不是synchronized方法,则能进入。
2. 如果这个方法内部调用了wait,则能进入其他的synchronized方法。
3. 其他方法如果都加了synchronized,并且内部没有调用wait,则不能进入。
3. 如果其他方法是static,它的同步锁是当前类的字节码,与非静态方法不能同步,所以能进入。