文章目录
方式一:继承Thread类
public class MyThread extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
if(i%2==0){
try {
sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(i);
}
}
}
}
MyThread t1=new MyThread();
t1.setName("线程A");
t1.start();
创建匿名类方式
new Thread("线程二"){
@Override
public void run() {
for(int i=0;i<100;i++){
if(i%2==0){
System.out.println(Thread.currentThread().getName()+"--->"+i);
}
}
}
}.start();
线程的常用方法
- start():启动当前线程;调用当前线程的run();
MyThread t1=new MyThread();
t1.start();
- currentThread():静态方法,获取当前代码的线程;
- getName():获取当前线程的名字;
Thread.currentThread().getName();
- getPriority():获取当前线程的优先级
Thread.currentThread().getPriority();
- setPriority():设置线程优先级;
MyThread t1=new MyThread();
t1.setPriority(Thread.MAX_PRIORITY);
- setName():设置当前线程的名字;
t1.setName("线程A");
Thread.currentThread().setName("主线程");
-
yield():释放当前cpu的执行权;
-
sleep():让当前线程“睡眠”指定的毫秒。在指定的毫秒时间内,当前线程是阻塞状态;
-
join():在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态。
this.join();
- isAlive():判断当前线程是否存活
System.out.println(t1.isAlive());
方式二:实现Runnable接口
public class TicketThread1 implements Runnable {
private static int tickets=100;
@Override
public void run() {
while (true) {
synchronized (this) {
if (tickets > 0) {
try {
sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+": sell ticket number:\t" + tickets);
tickets--;
} else {
break;
}
}
}
}
}
public class TicketThreadTest1 {
public static void main(String[] args) {
TicketThread1 window=new TicketThread1();
Thread thread=new Thread(window);
Thread thread1=new Thread(window);
Thread thread2=new Thread(window);
thread.setName("窗口1");
thread1.setName("窗口2");
thread2.setName("窗口3");
thread.start();
thread1.start();
thread2.start();
}
}
线程安全问题
同步代码块的方式
- 处理继承Thread类的线程安全问题
synchronized (TicketThread.class) {
if (tickets > 0) {
try {
sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(getName() + ":卖票,票号:\t" + tickets);
tickets--;
} else {
break;
}
}
- 处理实现Runnable接口的线程安全问题
synchronized (this) {
if (tickets > 0) {
try {
sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+": sell ticket number:\t" + tickets);
tickets--;
} else {
break;
}
}
同步方法的方式
- 处理继承Thread类的线程安全问题
public static synchronized void show(){
if (tickets > 0) {
try {
sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("sell ticket number:\t" + tickets);
tickets--;
}
}
-
继承Thread类的方式:需要定义static类型的属性和方法;例如: public static int tickets=100;
-
处理实现Runnable接口的线程安全问题
public synchronized void show(){
if (tickets > 0) {
try {
sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("sell ticket number:\t" + tickets);
tickets--;
}
}
Lock锁方式
private int tickets=100;
private ReentrantLock lock=new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock();
if(tickets>0){
try {
sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+":sell ticket number is: "+tickets);
tickets--;
}else {
break;
}
try{
}finally {
lock.unlock();
}
}
}
线程通信相关的方法
- wait():执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
- notify():执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个。
- notifyAll():执行此方法,就会唤醒所有被wait的线程。
sleep()与wait()的区别
- 相同点:都可以使当前线程进入阻塞状态;
- 不同点
- 声明的位置不同:Thread类中声明sleep(),Object类声明wait();
- 调用场景不同:sleep()任何场景都可以调用;wait()必须在同步代码块或同步方法中调用;
- 是否释放同步监视器:都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁;
class Number implements Runnable{
private int number =1;
@Override
public void run() {
while (true){
synchronized (this) {
this.notifyAll();
if (number <= 100) {
System.out.println(Thread.currentThread().getName() + " : " + number);
number++;
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} else {
break;
}
}
}
}
}
方式三:实现Callable接口
Callable接口的特点
- call()可以有返回值的;
- call()可以抛出异常,被外面的操作捕获,获取异常的信息;
- Callable是支持泛型的;
public class NumSum implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 100; i++) {
System.out.println(i);
sum++;
}
return sum;
}
}
public class ThreadNewTest {
public static void main(String[] args) {
NumSum numSum=new NumSum();
FutureTask<Integer> futureTask=new FutureTask<Integer>(numSum);
new Thread(futureTask).start();
try {
Integer o = futureTask.get();//get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值
System.out.println("sum is : \t"+o.toString());
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
}
方式四:使用线程池
使用线程池的好处
- 提高响应速度(减少了创建新线程的时间)
- 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
- 便于线程管理
- corePoolSize:核心池的大小
- maximumPoolSize:最大线程数
- keepAliveTime:线程没有任务时最多保持多长时间后会终止
public class ThreadPoolTest {
public static void main(String[] args) {
//提供指定线程数量的线程池
ExecutorService service = Executors.newFixedThreadPool(10);
ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
//设置线程池的属性
// System.out.println(service.getClass());
// service1.setCorePoolSize(15);
// service1.setKeepAliveTime();
//执行指定的线程的操作。需要提供实现Runnable接口或Callable接口实现类的对象
service.execute(new NumberThread());//适合适用于Runnable
service.execute(new NumberThread1());//适合适用于Runnable
// service.submit(Callable callable);//适合使用于Callable
//3.关闭连接池
service.shutdown();
}
}
文章介绍了Java中创建线程的四种方式:继承Thread类、实现Runnable接口、实现Callable接口以及使用线程池。同时,详细讨论了线程安全问题的解决办法,包括同步代码块、同步方法和Lock锁。此外,还提到了线程通信的相关方法如sleep()和wait()的区别,以及使用线程池的优点。
3418

被折叠的 条评论
为什么被折叠?



