进程与线程的关系
一个程序至少有一个进程,一个进程至少有一个线程,一个线程只属于一个进程.
火车站可以看作一个进程
火车站中的售票窗口可以看作一个线程
实现线程的多种方式
实现线程的第一种方式
通过继承Thread实现
public class Main {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start(); //开启一个新的分支,自动调用run方法
for (int i = 0; i < 1000; i++) {
System.out.println("主线程---->" + i);
}
}
}
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(this.getName() + "线程---->" + i);
}
}
}
实现线程的第二种方式
通过实现Runnable接口实现
public class Main {
public static void main(String[] args) {
MyRunning myRunning = new MyRunning(); //创建一个可运行的对象
Thread thread = new Thread(myRunning); //封装为线程对象
thread.start();
for (int i = 0; i < 300; i++) {
System.out.println("主线程--->" + i);
}
}
}
class MyRunning implements Runnable {
@Override
public void run() {
for (int i = 0; i < 300; i++) {
System.out.println("分支线程--->" + i);
}
}
}
实现线程的第三种方式
实现Callable接口 //可以获取线程的返回值
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable myCallable = new MyCallable();
FutureTask task = new FutureTask(myCallable); //未来任务类
Thread t = new Thread(task);
t.start();
for (int i = 0; i < 300; i++) {
System.out.println("主线程-->" + i);
}
Object obj = task.get(); //获取返回值
System.out.println(obj);
}
}
class MyCallable implements Callable {
@Override
public Object call() throws Exception {
for (int i = 0; i < 300; i++) {
System.out.println("f线程-->" + i);
}
return 10;
}
}
线程的一些方法
getName
this.getName();//获取线程名字
注:该方法需要在线程内才可使用,继承Runnable接口不能使用,原因是因为它并不是一个线程只是一个对象,需要获取当前线程才能使用,如下
@Override
public void run() {
Thread nowThread = Thread.currentThread(); //获取当前线程
for (int i = 0; i < 300; i++) {
System.out.println(nowThread.getName() + "线程--->" + i);
// System.out.println(this.getName()+"线程--->" + i);
// System.out.println(super.getName()+"线程--->" + i);
}
}
sleep
Thread.sleep(1000*5) //休眠5s
interrupt
thread.interrupt(); //其作用是中断此线程(此线程不一定是当前线程,而是指调用该方法的Thread实例所代表的线程),但实际上只是给线程设置一个中断标志,线程仍会继续运行。
public class Main {
public static void main(String[] args) throws InterruptedException {
MyRunning myRunning = new MyRunning();
Thread thread = new Thread(myRunning);
thread.start();
System.out.println("---主线程---");
Thread.sleep(1000 * 5);
thread.interrupt(); //通过异常终止休眠
}
}
class MyRunning implements Runnable {
@Override
public void run() {
try {
Thread.sleep(1000 * 60);
} catch (InterruptedException e) {
e.printStackTrace(); //打印信息,如果为throw异常,则不向下运行
}
System.out.println("hello word");
}
}
setPriority
设置线程优先级
默认为5,10最高,1最低
Thread thread = new Thread();
thread .setPriority(10);
yield
Thread.yield();
线程让位
join
//线程合并
Thread thread = new Thread();
thread.join();
thread线程先执行,被合并的线程后执行
关于线程安全
线程不安全的条件
1.多线程并发
2.有共享数据
3.共享数据有修改的行为
解决线程安全
线程同步机制
synchronized (this){ //this指当前对象,想同步哪一个对象填哪一个对象
//线程同步代码块
}
注:建议使用在实例方法上。效率高
生产者和消费者模式
其中的用到的方法
wait()方法的作用
Object o=new Object();
o.wait();
让正在o对象上活动的线程进入等待状态,无限期等待,直到被唤醒。
notify()方法的作用
o.notify();
将正在o对象上等待的线程唤醒
public class Main {
public static void main(String[] args) {
List list = new ArrayList();
Thread thread1 = new Thread(new Produce(list)); //生产者线程
Thread thread2 = new Thread(new Consume(list)); //消费者线程
thread1.setName("生产者");
thread2.setName("消费者");
thread1.start();
thread2.start();
}
}
class Produce implements Runnable { //生产者类
private List list;
public Produce(List list) {
this.list = list;
}
@Override
public void run() {
while (true) {
synchronized (list) {
if (list.size() > 0) {
try {
list.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
Object o = new Object();
list.add(o);
System.out.println(Thread.currentThread().getName() + "生产了一个产品");
list.notify();
}
}
}
}
class Consume implements Runnable { //消费者类
private List list;
public Consume(List list) {
this.list = list;
}
@Override
public void run() {
while (true) {
synchronized (list) {
if (list.size() == 0) {
try {
list.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
list.remove(0);
System.out.println(Thread.currentThread().getName() + "消费了一个产品");
list.notify();
}
}
}
}