java 手写题
      1.创建线程  共有四种方式可以创建线程,分别是:继承Thread类、实现runnable接口、实现Callable接口、线程池创建线程  详细创建方式参考下面代码:  ① 继承Thread类  public class MyThread extends Thread {    @Override    public void run() {        System.out.println("MyThread...run...");    }        public static void main(String[] args) {        // 创建MyThread对象        MyThread t1 = new MyThread() ;        MyThread t2 = new MyThread() ;        // 调用start方法启动线程        t1.start();        t2.start();    }    }  ② 实现runnable接口  public class MyRunnable implements Runnable{    @Override    public void run() {        System.out.println("MyRunnable...run...");    }    public static void main(String[] args) {        // 创建MyRunnable对象        MyRunnable mr = new MyRunnable() ;        // 创建Thread对象        Thread t1 = new Thread(mr) ;        Thread t2 = new Thread(mr) ;        // 调用start方法启动线程        t1.start();        t2.start();    }}  ③ 实现Callable接口  public class MyCallable implements Callable<String> {//MyCallable类实现了Callable<String>接口,该接口是一个泛型接口,指定了call()方法的返回类型为String    @Override    public String call() throws Exception {//call方法可以抛出异常        System.out.println("MyCallable...call...");        return "OK";    }    public static void main(String[] args) throws ExecutionException, InterruptedException {        // 创建MyCallable对象        MyCallable mc = new MyCallable() ;        //创建FutureTask<String>对象ft,并将mc作为参数传入构造方法,用于封装可调用对象        FutureTask<String> ft = new FutureTask<String>(mc) ;        //通过将Callable对象封装在FutureTask中,可以在多线程环境下执行任务,并获取任务执行结果。        // 创建Thread对象        Thread t1 = new Thread(ft) ;        Thread t2 = new Thread(ft) ;        // 调用start方法启动线程        t1.start();        //调用ft.get()方法获取执行结果,此方法会阻塞当前线程直到结果返回。        String result = ft.get();        // 输出        System.out.println(result);    }}//输出结果MyCallable...call...OK  ④ 线程池创建线程  public class MyExecutors implements Runnable{    @Override    public void run() {        System.out.println("MyRunnable...run...");    }    public static void main(String[] args) {        // 创建线程池对象。获取ExecutorService实例,生产禁用,需要手动创建线程池        ExecutorService threadPool = Executors.newFixedThreadPool(3);        //通过threadPool.submit(new MyExecutors())来向线程池提交任务。        threadPool.submit(new MyExecutors()) ;        //调用 Executor 的 shutdown() 方法会等待线程都执行完毕之后再关闭,但是如果调用的是 shutdownNow() 方法,则相当于调用每个线程的 interrupt() 方法。        threadPool.shutdown();    }}  2.手写线程池  public class ThreadPoolExecutorTest {//它创建了一个线程池,最大线程数为5,核心线程数为2,空闲线程存活时间为2秒,任务队列容量为3。然后向线程池提交了5个任务,每个任务打印当前线程的名称和"ok"。最后关闭线程池。//跑6条线程,那么6 >= 核心线程数+阻塞队列中的线程数,就会启用其他三条线程中的一个//跑8条线程,那么8 >= 核心线程数+阻塞队列中的线程数,就会启用其他三条线程中的三个//跑9条线程,那么9 >= 核心线程数+阻塞队列中的线程数,且9 > 最大线程数(5) + 阻塞队列中的线程数(8),则会触发拒绝策略,这里使用的拒绝策略是AbortPolicy,也就是拒绝处理,并抛出异常    public static void main(String[] args) {        ExecutorService threadPool = new ThreadPoolExecutor(                2,                5,                2,                TimeUnit.SECONDS,                new LinkedBlockingQueue<>(3),                Executors.defaultThreadFactory(),                new ThreadPoolExecutor.AbortPolicy()            //当线程池无法接受新任务时,会触发拒绝策略,内置的拒绝策略有四种:   AbortPolicy:默认策略,直接抛出 RejectedExecutionException 异常。   CallerRunsPolicy:由调用者线程执行任务。   DiscardPolicy:默默地丢弃任务,没有任何异常抛出。   DiscardOldestPolicy:尝试抛弃队列中最旧的任务,然后重新尝试提交当前任务。        );        try {            for (int i = 1; i <= 5 ; i++) {                threadPool.execute(()-> {                    System.out.println(Thread.currentThread().getName() + "ok");                });            }        } catch (Exception e) {            e.printStackTrace();        } finally {            threadPool.shutdown();        }    }}/** * pool-1-thread-1ok * pool-1-thread-2ok * pool-1-thread-2ok * pool-1-thread-2ok * pool-1-thread-1ok */  3. 新建 T1、T2、T3 三个线程,如何保证它们按顺序执行?  可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行。  代码举例:  为了确保三个线程的顺序你应该先启动最后一个(T3调用T2,T2调用T1),这样T1就会先完成而T3最后完成  public class JoinTest {    public static void main(String[] args) {        // 创建线程对象        Thread t1 = new Thread(() -> {            System.out.println("t1");        }) ;        Thread t2 = new Thread(() -> {            try {                t1.join();                          // 加入线程t1,只有t1线程执行完毕以后,再次执行该线程            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println("t2");        }) ;        Thread t3 = new Thread(() -> {            try {                t2.join();                              // 加入线程t2,只有t2线程执行完毕以后,再次执行该线程            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println("t3");        }) ;        // 启动线程        t1.start();        t2.start();        t3.start();    }}  4.synchronized解决抢票超卖问题  如下抢票的代码,如果不加锁,就会出现超卖或者一张票卖给多个人  Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】,其它线程再想获取这个【对象锁】时就会阻塞住  public class TicketDemo {    static Object lock = new Object();    int ticketNum = 10;    public synchronized void getTicket() {        synchronized (this) {            if (ticketNum <= 0) {                return;            }            System.out.println(Thread.currentThread().getName() + "抢到一张票,剩余:" + ticketNum);            // 非原子性操作            ticketNum--;        }    }    public static void main(String[] args) {        TicketDemo ticketDemo = new TicketDemo();        for (int i = 0; i < 20; i++) {            new Thread(() -> {                ticketDemo.getTicket();            }).start();        }    }}  5.线程死锁代码  死锁:线程死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象。若无外力作用,它们都将无法推进下去。  package com.itheima.basic;import static java.lang.Thread.sleep;public class Deadlock { //t1 线程获得A资源,接下来想获取B资源 //t2 线程获得B资源,接下来想获取A资源     public static void main(String[] args) {        Object A = new Object();        Object B = new Object();        Thread t1 = new Thread(() -> {            synchronized (A) {                System.out.println(Thread.currentThread() + "get resource1");                try {                    sleep(1000);                } catch (InterruptedException e) {                    throw new RuntimeException(e);                }                synchronized (B) {                    System.out.println(Thread.currentThread() + "get resource1");                                    }            }        }, "t1");        Thread t2 = new Thread(() -> {            synchronized (B) {                System.out.println(Thread.currentThread() + "get resource1");                try {                    sleep(500);                } catch (InterruptedException e) {                    throw new RuntimeException(e);                }                synchronized (A) {                    System.out.println(Thread.currentThread() + "get resource1");                                   }            }        }, "t2");        t1.start();        t2.start();    }}  6.Semaphore信号量  synchronized 和 ReentrantLock 都是一次只允许一个线程访问某个资源,而Semaphore(信号量)可以用来控制同时访问特定资源的线程数量。  以下代码模拟了对某个服务的并发请求,每次只能有 3 个客户端同时访问,请求总数为 10。  public class SemaphoreExample {    public static void main(String[] args) {        final int clientCount = 3;        final int totalRequestCount = 10;        //意味着最多允许clientCount个线程同时执行        Semaphore semaphore = new Semaphore(clientCount);        ExecutorService executorService = Executors.newCachedThreadPool();        for (int i = 0; i < totalRequestCount; i++) {            executorService.execute(()->{                try {                    //调用semaphore.acquire()方法获取信号量。如果当前信号量的可用资源数量大于0,则会直接获取资源并继续执行;否则,线程将被阻塞,直到有可用资源为止。                    semaphore.acquire();                    //在获取资源后,打印出当前信号量的可用资源数量,即semaphore.availablePermits()。                    System.out.print(semaphore.availablePermits() + " ");                } catch (InterruptedException e) {                    e.printStackTrace();                } finally {                    //release()方法释放了一个信号量                    semaphore.release();                }            });        }        //调用executorService.shutdown()方法关闭线程池        executorService.shutdown();    }  7. CyclicBarrier(同步屏障)  yclicBarrier(同步屏障),用于一组线程互相等待到某个状态,然后这组线程再同时执行。  通过CyclicBarrier实现了一种线程同步机制,即在所有线程都到达某个点之前,它们会一直等待;当所有线程都到达该点后,才会继续执行后续代码。  public class CyclicBarrierExample {    public static void main(String[] args) {        final int totalThread = 10;//表示线程总数        CyclicBarrier cyclicBarrier = new CyclicBarrier(totalThread);        ExecutorService executorService = Executors.newCachedThreadPool();        for (int i = 0; i < totalThread; i++) {            executorService.execute(() -> {                System.out.print("before..");                try {                    //调用cyclicBarrier.await()进行等待,直到所有线程都到达屏障点。                    cyclicBarrier.await();                } catch (InterruptedException | BrokenBarrierException e) {                    e.printStackTrace();                }                System.out.print("after..");            });        }        //调用executorService.shutdown()关闭线程池。        executorService.shutdown();    }}//输出结果before..before..before..before..before..before..before..before..before..before..after..after..after..after..after..after..after..after..after..after..  7.CountDownLatch倒计时锁  CountDownLatch倒计时锁用于某个线程等待其他线程执行完任务再执行,与thread.join()功能类似。常见的应用场景是开启多个线程同时执行某个任务,等到所有任务执行完再执行特定操作,如汇总统计结果     其中构造参数用来初始化等待计数值   await() 用来等待计数归零,调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行;等待timeout时间后count值还没变为0的话就会继续执行   countDown() 用来让计数减一    在这个例子中,我们创建了一个CountDownLatch实例,其计数器初始值为3。然后创建了3个线程,每个线程执行一个Worker任务。Worker任务完成后,调用latch.countDown()将计数器减一。主线程通过调用latch.await()等待所有子线程完成任务(即计数器变为0)。当所有子线程完成任务后,主线程继续执行并输出"所有子线程任务已完成"。  import java.util.concurrent.CountDownLatch;public class CountDownLatchExample {    public static void main(String[] args) throws InterruptedException {        int numberOfThreads = 3;        CountDownLatch latch = new CountDownLatch(numberOfThreads);        for (int i = 0; i < numberOfThreads; i++) {            new Thread(new Worker(latch)).start();        }        // 主线程等待所有子线程完成任务        latch.await();        System.out.println("所有子线程任务已完成");    }    static class Worker implements Runnable {        private final CountDownLatch latch;        public Worker(CountDownLatch latch) {            this.latch = latch;        }        @Override        public void run() {            try {                // 模拟耗时任务                Thread.sleep((long) (Math.random() * 1000));                System.out.println(Thread.currentThread().getName() + " 完成任务");            } catch (InterruptedException e) {                e.printStackTrace();            } finally {                // 完成任务后,计数器减一                latch.countDown();            }        }    }}Thread-2 完成任务Thread-1 完成任务Thread-0 完成任务所有子线程任务已完成  8.重写equals()的例子  在这个示例中,我们创建了一个Person类,包含name和age两个属性。我们重写了hashCode()方法,首先定义一个初始值为17的变量result,然后分别将name和age的哈希值乘以31并加到result上,最后返回result作为对象的哈希码值。这样做的目的是为了让不同的对象尽可能地产生不同的哈希码值,从而提高哈希表等数据结构的性能。  public class Person {    private String name;    private int age;    // 构造函数和其他方法...    @Override    public boolean equals(Object obj) {        if (this == obj) {            return true;        }        if (obj == null || getClass() != obj.getClass()) {            return false;        }        Person person = (Person) obj;        return age == person.age && name.equals(person.name);    }    @Override    public int hashCode() {        int result = 17; // 初始值        result = 31 * result + name.hashCode(); // 使用字符串的hashCode()方法计算哈希值        result = 31 * result + age; // 直接将年龄加入哈希值计算        return result;    }}  9.约瑟夫环问题  约瑟夫环问题的故事背景源自于历史学家约瑟夫斯·弗拉维奥·约瑟夫的《犹太战争》中描述的一个历史事件。在这个问题中,一群人围成一圈,从某个人开始报数,每报到一个特定的数字,那个人就会离开圈子,然后从下一个人开始重新报数,直到最后只剩下一个人。这个问题的目的是找出最后留下的那个人最初的位置。  #include <iostream>using namespace std;// 定义链表节点结构体struct Node {    int data; // 节点数据    Node* next; // 指向下一个节点的指针};// 创建循环链表Node* createList(int n) {    Node* head = new Node(); // 创建头节点    head->data = 1;    head->next = NULL;    Node* temp = head; // 临时指针,用于连接节点    for (int i = 2; i <= n; i++) {        Node* newNode = new Node(); // 创建新节点        newNode->data = i;        newNode->next = NULL;  
点赞 158
评论 18
全部评论
{"pureText":"😋","imgs":[]}
点赞 回复 分享
发布于 08-14 00:48 北京

相关推荐

点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
11-21 19:05
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务